annotate view/Pane.cpp @ 454:e2a40fdadd8c

Various fixes: * Fix handling of HTTP redirects (avoiding crashes... I hope) * Fix failure to delete FFT models when a feature extraction model transformer was abandoned (also a cause of crashes in the past) * Fix deadlock when said transform was abandoned before its source model was ready because the session was being cleared (and so the source model would never be ready)
author Chris Cannam
date Fri, 28 Nov 2008 13:36:13 +0000
parents 76cd1c89eb06
children 035d62c4cddf
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@264 7 This file copyright 2006-2007 Chris Cannam and QMUL.
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 "Pane.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/RealTime.h"
Chris@127 21 #include "base/Profiler.h"
Chris@128 22 #include "ViewManager.h"
Chris@376 23 #include "widgets/CommandHistory.h"
Chris@376 24 #include "widgets/TextAbbrev.h"
Chris@338 25 #include "base/Preferences.h"
Chris@127 26 #include "layer/WaveformLayer.h"
Chris@127 27
Chris@326 28 //!!! ugh
Chris@326 29 #include "data/model/WaveFileModel.h"
Chris@326 30
Chris@127 31 #include <QPaintEvent>
Chris@127 32 #include <QPainter>
Chris@257 33 #include <QBitmap>
Chris@312 34 #include <QDragEnterEvent>
Chris@312 35 #include <QDropEvent>
Chris@257 36 #include <QCursor>
Chris@316 37 #include <QTextStream>
Chris@316 38
Chris@127 39 #include <iostream>
Chris@127 40 #include <cmath>
Chris@127 41
Chris@133 42 //!!! for HUD -- pull out into a separate class
Chris@133 43 #include <QFrame>
Chris@133 44 #include <QGridLayout>
Chris@133 45 #include <QPushButton>
Chris@133 46 #include "widgets/Thumbwheel.h"
Chris@172 47 #include "widgets/Panner.h"
Chris@188 48 #include "widgets/RangeInputDialog.h"
Chris@189 49 #include "widgets/NotifyingPushButton.h"
Chris@133 50
Chris@282 51 #include "widgets/KeyReference.h" //!!! should probably split KeyReference into a data class in base and another that shows the widget
Chris@282 52
Chris@363 53 //#define DEBUG_PANE
Chris@363 54
Chris@127 55 using std::cerr;
Chris@127 56 using std::endl;
Chris@127 57
Chris@267 58 QCursor *Pane::m_measureCursor1 = 0;
Chris@267 59 QCursor *Pane::m_measureCursor2 = 0;
Chris@262 60
Chris@127 61 Pane::Pane(QWidget *w) :
Chris@127 62 View(w, true),
Chris@127 63 m_identifyFeatures(false),
Chris@127 64 m_clickedInRange(false),
Chris@127 65 m_shiftPressed(false),
Chris@127 66 m_ctrlPressed(false),
Chris@127 67 m_navigating(false),
Chris@127 68 m_resizing(false),
Chris@343 69 m_editing(false),
Chris@343 70 m_releasing(false),
Chris@133 71 m_centreLineVisible(true),
Chris@222 72 m_scaleWidth(0),
Chris@237 73 m_headsUpDisplay(0),
Chris@237 74 m_vpan(0),
Chris@237 75 m_hthumb(0),
Chris@237 76 m_vthumb(0),
Chris@290 77 m_reset(0),
Chris@290 78 m_mouseInWidget(false)
Chris@127 79 {
Chris@127 80 setObjectName("Pane");
Chris@127 81 setMouseTracking(true);
Chris@312 82 setAcceptDrops(true);
Chris@133 83
Chris@133 84 updateHeadsUpDisplay();
Chris@133 85 }
Chris@133 86
Chris@133 87 void
Chris@133 88 Pane::updateHeadsUpDisplay()
Chris@133 89 {
Chris@382 90 Profiler profiler("Pane::updateHeadsUpDisplay");
Chris@187 91
Chris@192 92 if (!isVisible()) return;
Chris@192 93
Chris@132 94 /*
Chris@132 95 int count = 0;
Chris@132 96 int currentLevel = 1;
Chris@132 97 int level = 1;
Chris@132 98 while (true) {
Chris@132 99 if (getZoomLevel() == level) currentLevel = count;
Chris@132 100 int newLevel = getZoomConstraintBlockSize(level + 1,
Chris@132 101 ZoomConstraint::RoundUp);
Chris@132 102 if (newLevel == level) break;
Chris@132 103 if (newLevel == 131072) break; //!!! just because
Chris@132 104 level = newLevel;
Chris@132 105 ++count;
Chris@132 106 }
Chris@132 107
Chris@132 108 std::cerr << "Have " << count+1 << " zoom levels" << std::endl;
Chris@132 109 */
Chris@133 110
Chris@188 111 Layer *layer = 0;
Chris@188 112 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1);
Chris@188 113
Chris@133 114 if (!m_headsUpDisplay) {
Chris@133 115
Chris@133 116 m_headsUpDisplay = new QFrame(this);
Chris@133 117
Chris@133 118 QGridLayout *layout = new QGridLayout;
Chris@133 119 layout->setMargin(0);
Chris@133 120 layout->setSpacing(0);
Chris@133 121 m_headsUpDisplay->setLayout(layout);
Chris@133 122
Chris@133 123 m_hthumb = new Thumbwheel(Qt::Horizontal);
Chris@187 124 m_hthumb->setObjectName(tr("Horizontal Zoom"));
Chris@260 125 m_hthumb->setCursor(Qt::ArrowCursor);
Chris@173 126 layout->addWidget(m_hthumb, 1, 0, 1, 2);
Chris@133 127 m_hthumb->setFixedWidth(70);
Chris@133 128 m_hthumb->setFixedHeight(16);
Chris@133 129 m_hthumb->setDefaultValue(0);
Chris@165 130 m_hthumb->setSpeed(0.6);
Chris@133 131 connect(m_hthumb, SIGNAL(valueChanged(int)), this,
Chris@133 132 SLOT(horizontalThumbwheelMoved(int)));
Chris@189 133 connect(m_hthumb, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@189 134 connect(m_hthumb, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@172 135
Chris@172 136 m_vpan = new Panner;
Chris@260 137 m_vpan->setCursor(Qt::ArrowCursor);
Chris@172 138 layout->addWidget(m_vpan, 0, 1);
Chris@173 139 m_vpan->setFixedWidth(12);
Chris@172 140 m_vpan->setFixedHeight(70);
Chris@174 141 m_vpan->setAlpha(80, 130);
Chris@174 142 connect(m_vpan, SIGNAL(rectExtentsChanged(float, float, float, float)),
Chris@174 143 this, SLOT(verticalPannerMoved(float, float, float, float)));
Chris@188 144 connect(m_vpan, SIGNAL(doubleClicked()),
Chris@188 145 this, SLOT(editVerticalPannerExtents()));
Chris@189 146 connect(m_vpan, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@189 147 connect(m_vpan, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@172 148
Chris@133 149 m_vthumb = new Thumbwheel(Qt::Vertical);
Chris@187 150 m_vthumb->setObjectName(tr("Vertical Zoom"));
Chris@260 151 m_vthumb->setCursor(Qt::ArrowCursor);
Chris@172 152 layout->addWidget(m_vthumb, 0, 2);
Chris@133 153 m_vthumb->setFixedWidth(16);
Chris@133 154 m_vthumb->setFixedHeight(70);
Chris@133 155 connect(m_vthumb, SIGNAL(valueChanged(int)), this,
Chris@133 156 SLOT(verticalThumbwheelMoved(int)));
Chris@189 157 connect(m_vthumb, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@189 158 connect(m_vthumb, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@133 159
Chris@188 160 if (layer) {
Chris@188 161 RangeMapper *rm = layer->getNewVerticalZoomRangeMapper();
Chris@188 162 if (rm) m_vthumb->setRangeMapper(rm);
Chris@188 163 }
Chris@188 164
Chris@189 165 m_reset = new NotifyingPushButton;
Chris@260 166 m_reset->setCursor(Qt::ArrowCursor);
Chris@189 167 m_reset->setFixedHeight(16);
Chris@189 168 m_reset->setFixedWidth(16);
Chris@189 169 layout->addWidget(m_reset, 1, 2);
Chris@189 170 connect(m_reset, SIGNAL(clicked()), m_hthumb, SLOT(resetToDefault()));
Chris@189 171 connect(m_reset, SIGNAL(clicked()), m_vthumb, SLOT(resetToDefault()));
Chris@189 172 connect(m_reset, SIGNAL(clicked()), m_vpan, SLOT(resetToDefault()));
Chris@189 173 connect(m_reset, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@189 174 connect(m_reset, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@133 175 }
Chris@133 176
Chris@133 177 int count = 0;
Chris@133 178 int current = 0;
Chris@133 179 int level = 1;
Chris@133 180
Chris@137 181 //!!! pull out into function (presumably in View)
Chris@137 182 bool haveConstraint = false;
Chris@137 183 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end();
Chris@137 184 ++i) {
Chris@137 185 if ((*i)->getZoomConstraint() && !(*i)->supportsOtherZoomLevels()) {
Chris@137 186 haveConstraint = true;
Chris@137 187 break;
Chris@137 188 }
Chris@137 189 }
Chris@137 190
Chris@137 191 if (haveConstraint) {
Chris@137 192 while (true) {
Chris@137 193 if (getZoomLevel() == level) current = count;
Chris@137 194 int newLevel = getZoomConstraintBlockSize(level + 1,
Chris@137 195 ZoomConstraint::RoundUp);
Chris@137 196 if (newLevel == level) break;
Chris@137 197 level = newLevel;
Chris@137 198 if (++count == 50) break;
Chris@137 199 }
Chris@137 200 } else {
Chris@137 201 // if we have no particular constraints, we can really spread out
Chris@137 202 while (true) {
Chris@137 203 if (getZoomLevel() >= level) current = count;
Chris@137 204 int step = level / 10;
Chris@137 205 int pwr = 0;
Chris@137 206 while (step > 0) {
Chris@137 207 ++pwr;
Chris@137 208 step /= 2;
Chris@137 209 }
Chris@137 210 step = 1;
Chris@137 211 while (pwr > 0) {
Chris@137 212 step *= 2;
Chris@137 213 --pwr;
Chris@137 214 }
Chris@154 215 // std::cerr << level << std::endl;
Chris@137 216 level += step;
Chris@137 217 if (++count == 100 || level > 262144) break;
Chris@137 218 }
Chris@133 219 }
Chris@133 220
Chris@133 221 // std::cerr << "Have " << count << " zoom levels" << std::endl;
Chris@133 222
Chris@133 223 m_hthumb->setMinimumValue(0);
Chris@133 224 m_hthumb->setMaximumValue(count);
Chris@133 225 m_hthumb->setValue(count - current);
Chris@133 226
Chris@133 227 // std::cerr << "set value to " << count-current << std::endl;
Chris@133 228
Chris@133 229 // std::cerr << "default value is " << m_hthumb->getDefaultValue() << std::endl;
Chris@133 230
Chris@133 231 if (count != 50 && m_hthumb->getDefaultValue() == 0) {
Chris@133 232 m_hthumb->setDefaultValue(count - current);
Chris@133 233 // std::cerr << "set default value to " << m_hthumb->getDefaultValue() << std::endl;
Chris@133 234 }
Chris@133 235
Chris@204 236 bool haveVThumb = false;
Chris@204 237
Chris@133 238 if (layer) {
Chris@133 239 int defaultStep = 0;
Chris@133 240 int max = layer->getVerticalZoomSteps(defaultStep);
Chris@133 241 if (max == 0) {
Chris@133 242 m_vthumb->hide();
Chris@133 243 } else {
Chris@204 244 haveVThumb = true;
Chris@133 245 m_vthumb->show();
Chris@187 246 m_vthumb->blockSignals(true);
Chris@133 247 m_vthumb->setMinimumValue(0);
Chris@133 248 m_vthumb->setMaximumValue(max);
Chris@133 249 m_vthumb->setDefaultValue(defaultStep);
Chris@133 250 m_vthumb->setValue(layer->getCurrentVerticalZoomStep());
Chris@187 251 m_vthumb->blockSignals(false);
Chris@135 252
Chris@205 253 // std::cerr << "Vertical thumbwheel: min 0, max " << max
Chris@205 254 // << ", default " << defaultStep << ", value "
Chris@205 255 // << m_vthumb->getValue() << std::endl;
Chris@135 256
Chris@133 257 }
Chris@133 258 }
Chris@133 259
Chris@174 260 updateVerticalPanner();
Chris@174 261
Chris@133 262 if (m_manager && m_manager->getZoomWheelsEnabled() &&
Chris@133 263 width() > 120 && height() > 100) {
Chris@165 264 if (!m_headsUpDisplay->isVisible()) {
Chris@165 265 m_headsUpDisplay->show();
Chris@165 266 }
Chris@204 267 if (haveVThumb) {
Chris@204 268 m_headsUpDisplay->setFixedHeight(m_vthumb->height() + m_hthumb->height());
Chris@133 269 m_headsUpDisplay->move(width() - 86, height() - 86);
Chris@133 270 } else {
Chris@204 271 m_headsUpDisplay->setFixedHeight(m_hthumb->height());
Chris@204 272 m_headsUpDisplay->move(width() - 86, height() - 16);
Chris@133 273 }
Chris@133 274 } else {
Chris@133 275 m_headsUpDisplay->hide();
Chris@133 276 }
Chris@127 277 }
Chris@127 278
Chris@174 279 void
Chris@174 280 Pane::updateVerticalPanner()
Chris@174 281 {
Chris@174 282 if (!m_vpan || !m_manager || !m_manager->getZoomWheelsEnabled()) return;
Chris@174 283
Chris@208 284 // In principle we should show or hide the panner on the basis of
Chris@208 285 // whether the top layer has adjustable display extents, and we do
Chris@208 286 // that below. However, we have no basis for layout of the panner
Chris@208 287 // if the vertical scroll wheel is not also present. So if we
Chris@208 288 // have no vertical scroll wheel, we should remove the panner as
Chris@208 289 // well. Ideally any layer that implements display extents should
Chris@208 290 // implement vertical zoom steps as well, but they don't all at
Chris@208 291 // the moment.
Chris@208 292
Chris@208 293 Layer *layer = 0;
Chris@208 294 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1);
Chris@208 295 int discard;
Chris@208 296 if (layer && layer->getVerticalZoomSteps(discard) == 0) {
Chris@208 297 m_vpan->hide();
Chris@208 298 return;
Chris@208 299 }
Chris@208 300
Chris@174 301 float vmin, vmax, dmin, dmax;
Chris@174 302 if (getTopLayerDisplayExtents(vmin, vmax, dmin, dmax) && vmax != vmin) {
Chris@174 303 float y0 = (dmin - vmin) / (vmax - vmin);
Chris@174 304 float y1 = (dmax - vmin) / (vmax - vmin);
Chris@174 305 m_vpan->blockSignals(true);
Chris@174 306 m_vpan->setRectExtents(0, 1.0 - y1, 1, y1 - y0);
Chris@174 307 m_vpan->blockSignals(false);
Chris@174 308 m_vpan->show();
Chris@174 309 } else {
Chris@174 310 m_vpan->hide();
Chris@174 311 }
Chris@174 312 }
Chris@174 313
Chris@127 314 bool
Chris@127 315 Pane::shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos) const
Chris@127 316 {
Chris@127 317 QPoint discard;
Chris@127 318 bool b0, b1;
Chris@127 319
Chris@262 320 if (m_manager && m_manager->getToolMode() == ViewManager::MeasureMode) {
Chris@262 321 return false;
Chris@262 322 }
Chris@262 323
Chris@326 324 if (m_manager && !m_manager->shouldIlluminateLocalFeatures()) {
Chris@326 325 return false;
Chris@326 326 }
Chris@326 327
Chris@127 328 if (layer == getSelectedLayer() &&
Chris@127 329 !shouldIlluminateLocalSelection(discard, b0, b1)) {
Chris@127 330
Chris@127 331 pos = m_identifyPoint;
Chris@127 332 return m_identifyFeatures;
Chris@127 333 }
Chris@127 334
Chris@127 335 return false;
Chris@127 336 }
Chris@127 337
Chris@127 338 bool
Chris@127 339 Pane::shouldIlluminateLocalSelection(QPoint &pos,
Chris@127 340 bool &closeToLeft,
Chris@127 341 bool &closeToRight) const
Chris@127 342 {
Chris@127 343 if (m_identifyFeatures &&
Chris@127 344 m_manager &&
Chris@127 345 m_manager->getToolMode() == ViewManager::EditMode &&
Chris@127 346 !m_manager->getSelections().empty() &&
Chris@127 347 !selectionIsBeingEdited()) {
Chris@127 348
Chris@127 349 Selection s(getSelectionAt(m_identifyPoint.x(),
Chris@127 350 closeToLeft, closeToRight));
Chris@127 351
Chris@127 352 if (!s.isEmpty()) {
Chris@127 353 if (getSelectedLayer() && getSelectedLayer()->isLayerEditable()) {
Chris@127 354
Chris@127 355 pos = m_identifyPoint;
Chris@127 356 return true;
Chris@127 357 }
Chris@127 358 }
Chris@127 359 }
Chris@127 360
Chris@127 361 return false;
Chris@127 362 }
Chris@127 363
Chris@127 364 bool
Chris@127 365 Pane::selectionIsBeingEdited() const
Chris@127 366 {
Chris@127 367 if (!m_editingSelection.isEmpty()) {
Chris@127 368 if (m_mousePos != m_clickPos &&
Chris@127 369 getFrameForX(m_mousePos.x()) != getFrameForX(m_clickPos.x())) {
Chris@127 370 return true;
Chris@127 371 }
Chris@127 372 }
Chris@127 373 return false;
Chris@127 374 }
Chris@127 375
Chris@127 376 void
Chris@127 377 Pane::setCentreLineVisible(bool visible)
Chris@127 378 {
Chris@127 379 m_centreLineVisible = visible;
Chris@127 380 update();
Chris@127 381 }
Chris@127 382
Chris@127 383 void
Chris@127 384 Pane::paintEvent(QPaintEvent *e)
Chris@127 385 {
Chris@127 386 // Profiler profiler("Pane::paintEvent", true);
Chris@127 387
Chris@127 388 QPainter paint;
Chris@127 389
Chris@127 390 QRect r(rect());
Chris@261 391 if (e) r = e->rect();
Chris@127 392
Chris@127 393 View::paintEvent(e);
Chris@127 394
Chris@127 395 paint.begin(this);
Chris@339 396 setPaintFont(paint);
Chris@338 397
Chris@261 398 if (e) paint.setClipRect(r);
Chris@127 399
Chris@259 400 ViewManager::ToolMode toolMode = m_manager->getToolMode();
Chris@259 401
Chris@127 402 if (m_manager &&
Chris@290 403 // !m_manager->isPlaying() &&
Chris@290 404 m_mouseInWidget &&
Chris@259 405 toolMode == ViewManager::MeasureMode) {
Chris@127 406
Chris@127 407 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
Chris@127 408 --vi;
Chris@127 409
Chris@127 410 std::vector<QRect> crosshairExtents;
Chris@127 411
Chris@127 412 if ((*vi)->getCrosshairExtents(this, paint, m_identifyPoint,
Chris@127 413 crosshairExtents)) {
Chris@127 414 (*vi)->paintCrosshairs(this, paint, m_identifyPoint);
Chris@127 415 break;
Chris@127 416 } else if ((*vi)->isLayerOpaque()) {
Chris@127 417 break;
Chris@127 418 }
Chris@127 419 }
Chris@127 420 }
Chris@127 421
Chris@268 422 Layer *topLayer = getTopLayer();
Chris@277 423 bool haveSomeTimeXAxis = false;
Chris@268 424
Chris@258 425 const Model *waveformModel = 0; // just for reporting purposes
Chris@326 426 const Model *workModel = 0;
Chris@326 427
Chris@127 428 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
Chris@127 429 --vi;
Chris@277 430 if (!haveSomeTimeXAxis && (*vi)->hasTimeXAxis()) {
Chris@277 431 haveSomeTimeXAxis = true;
Chris@277 432 }
Chris@127 433 if (dynamic_cast<WaveformLayer *>(*vi)) {
Chris@127 434 waveformModel = (*vi)->getModel();
Chris@326 435 workModel = waveformModel;
Chris@326 436 } else {
Chris@326 437 Model *m = (*vi)->getModel();
Chris@326 438 if (dynamic_cast<WaveFileModel *>(m)) {
Chris@326 439 workModel = m;
Chris@326 440 } else if (m && dynamic_cast<WaveFileModel *>(m->getSourceModel())) {
Chris@326 441 workModel = m->getSourceModel();
Chris@326 442 }
Chris@127 443 }
Chris@326 444
Chris@326 445 if (waveformModel && workModel && haveSomeTimeXAxis) break;
Chris@258 446 }
Chris@127 447
Chris@261 448 m_scaleWidth = 0;
Chris@261 449
Chris@261 450 if (m_manager && m_manager->shouldShowVerticalScale() && topLayer) {
Chris@261 451 drawVerticalScale(r, topLayer, paint);
Chris@261 452 }
Chris@261 453
Chris@326 454 if (m_identifyFeatures &&
Chris@326 455 m_manager && m_manager->shouldIlluminateLocalFeatures() &&
Chris@326 456 topLayer) {
Chris@261 457 drawFeatureDescription(topLayer, paint);
Chris@261 458 }
Chris@261 459
Chris@261 460 int sampleRate = getModelsSampleRate();
Chris@261 461 paint.setBrush(Qt::NoBrush);
Chris@261 462
Chris@261 463 if (m_centreLineVisible &&
Chris@261 464 m_manager &&
Chris@261 465 m_manager->shouldShowCentreLine()) {
Chris@277 466 drawCentreLine(sampleRate, paint, !haveSomeTimeXAxis);
Chris@261 467 }
Chris@261 468
Chris@261 469 paint.setPen(QColor(50, 50, 50));
Chris@261 470
Chris@261 471 if (waveformModel &&
Chris@261 472 m_manager &&
Chris@261 473 m_manager->shouldShowDuration()) {
Chris@261 474 drawDurationAndRate(r, waveformModel, sampleRate, paint);
Chris@261 475 }
Chris@261 476
Chris@326 477 bool haveWorkTitle = false;
Chris@326 478
Chris@326 479 if (workModel &&
Chris@326 480 m_manager &&
Chris@326 481 m_manager->shouldShowWorkTitle()) {
Chris@326 482 drawWorkTitle(r, paint, workModel);
Chris@326 483 haveWorkTitle = true;
Chris@326 484 }
Chris@326 485
Chris@326 486 if (workModel &&
Chris@320 487 m_manager &&
Chris@320 488 m_manager->getAlignMode()) {
Chris@326 489 drawAlignmentStatus(r, paint, workModel, haveWorkTitle);
Chris@320 490 }
Chris@320 491
Chris@261 492 if (m_manager &&
Chris@261 493 m_manager->shouldShowLayerNames()) {
Chris@261 494 drawLayerNames(r, paint);
Chris@261 495 }
Chris@261 496
Chris@262 497 if (m_shiftPressed && m_clickedInRange &&
Chris@283 498 (toolMode == ViewManager::NavigateMode || m_navigating)) {
Chris@261 499
Chris@261 500 //!!! be nice if this looked a bit more in keeping with the
Chris@261 501 //selection block
Chris@262 502
Chris@262 503 paint.setPen(Qt::blue);
Chris@262 504 //!!! shouldn't use clickPos -- needs to use a clicked frame
Chris@262 505 paint.drawRect(m_clickPos.x(), m_clickPos.y(),
Chris@262 506 m_mousePos.x() - m_clickPos.x(),
Chris@262 507 m_mousePos.y() - m_clickPos.y());
Chris@261 508
Chris@262 509 }
Chris@261 510
Chris@266 511 if (toolMode == ViewManager::MeasureMode && topLayer) {
Chris@272 512 bool showFocus = false;
Chris@272 513 if (!m_manager || !m_manager->isPlaying()) showFocus = true;
Chris@272 514 topLayer->paintMeasurementRects(this, paint, showFocus, m_identifyPoint);
Chris@261 515 }
Chris@261 516
Chris@261 517 if (selectionIsBeingEdited()) {
Chris@261 518 drawEditingSelection(paint);
Chris@261 519 }
Chris@261 520
Chris@261 521 paint.end();
Chris@261 522 }
Chris@261 523
Chris@276 524 size_t
Chris@276 525 Pane::getVerticalScaleWidth() const
Chris@276 526 {
Chris@276 527 if (m_scaleWidth > 0) return m_scaleWidth;
Chris@276 528 else return 0;
Chris@276 529 }
Chris@276 530
Chris@261 531 void
Chris@261 532 Pane::drawVerticalScale(QRect r, Layer *topLayer, QPainter &paint)
Chris@261 533 {
Chris@258 534 Layer *scaleLayer = 0;
Chris@258 535
Chris@261 536 float min, max;
Chris@261 537 bool log;
Chris@261 538 QString unit;
Chris@258 539
Chris@261 540 // If the top layer has no scale and reports no display
Chris@261 541 // extents, but does report a unit, then the scale should be
Chris@261 542 // drawn from any underlying layer with a scale and that unit.
Chris@261 543 // If the top layer has no scale and no value extents at all,
Chris@261 544 // then the scale should be drawn from any underlying layer
Chris@261 545 // with a scale regardless of unit.
Chris@258 546
Chris@261 547 int sw = topLayer->getVerticalScaleWidth(this, paint);
Chris@258 548
Chris@261 549 if (sw > 0) {
Chris@261 550 scaleLayer = topLayer;
Chris@261 551 m_scaleWidth = sw;
Chris@258 552
Chris@261 553 } else {
Chris@258 554
Chris@261 555 bool hasDisplayExtents = topLayer->getDisplayExtents(min, max);
Chris@261 556 bool hasValueExtents = topLayer->getValueExtents(min, max, log, unit);
Chris@261 557
Chris@261 558 if (!hasDisplayExtents) {
Chris@258 559
Chris@261 560 if (!hasValueExtents) {
Chris@258 561
Chris@261 562 for (LayerList::iterator vi = m_layers.end();
Chris@261 563 vi != m_layers.begin(); ) {
Chris@261 564
Chris@261 565 --vi;
Chris@261 566
Chris@261 567 if ((*vi) == topLayer) continue;
Chris@261 568
Chris@261 569 sw = (*vi)->getVerticalScaleWidth(this, paint);
Chris@261 570
Chris@261 571 if (sw > 0) {
Chris@261 572 scaleLayer = *vi;
Chris@261 573 m_scaleWidth = sw;
Chris@261 574 break;
Chris@261 575 }
Chris@261 576 }
Chris@261 577 } else if (unit != "") { // && hasValueExtents && !hasDisplayExtents
Chris@258 578
Chris@261 579 QString requireUnit = unit;
Chris@261 580
Chris@261 581 for (LayerList::iterator vi = m_layers.end();
Chris@261 582 vi != m_layers.begin(); ) {
Chris@258 583
Chris@261 584 --vi;
Chris@258 585
Chris@261 586 if ((*vi) == topLayer) continue;
Chris@258 587
Chris@261 588 if ((*vi)->getDisplayExtents(min, max)) {
Chris@261 589
Chris@261 590 // search no further than this: if the
Chris@261 591 // scale from this layer isn't suitable,
Chris@261 592 // we'll have to draw no scale (else we'd
Chris@261 593 // risk ending up with the wrong scale)
Chris@261 594
Chris@261 595 if ((*vi)->getValueExtents(min, max, log, unit) &&
Chris@261 596 unit == requireUnit) {
Chris@261 597
Chris@261 598 sw = (*vi)->getVerticalScaleWidth(this, paint);
Chris@261 599 if (sw > 0) {
Chris@261 600 scaleLayer = *vi;
Chris@261 601 m_scaleWidth = sw;
Chris@261 602 }
Chris@258 603 }
Chris@261 604 break;
Chris@258 605 }
Chris@258 606 }
Chris@258 607 }
Chris@127 608 }
Chris@258 609 }
Chris@127 610
Chris@258 611 if (!scaleLayer) m_scaleWidth = 0;
Chris@258 612
Chris@258 613 if (m_scaleWidth > 0 && r.left() < m_scaleWidth) {
Chris@127 614
Chris@127 615 // Profiler profiler("Pane::paintEvent - painting vertical scale", true);
Chris@127 616
Chris@127 617 // std::cerr << "Pane::paintEvent: calling paint.save() in vertical scale block" << std::endl;
Chris@258 618 paint.save();
Chris@258 619
Chris@287 620 paint.setPen(getForeground());
Chris@287 621 paint.setBrush(getBackground());
Chris@258 622 paint.drawRect(0, -1, m_scaleWidth, height()+1);
Chris@258 623
Chris@258 624 paint.setBrush(Qt::NoBrush);
Chris@258 625 scaleLayer->paintVerticalScale
Chris@258 626 (this, paint, QRect(0, 0, m_scaleWidth, height()));
Chris@258 627
Chris@258 628 paint.restore();
Chris@258 629 }
Chris@261 630 }
Chris@261 631
Chris@261 632 void
Chris@261 633 Pane::drawFeatureDescription(Layer *topLayer, QPainter &paint)
Chris@261 634 {
Chris@261 635 QPoint pos = m_identifyPoint;
Chris@261 636 QString desc = topLayer->getFeatureDescription(this, pos);
Chris@261 637
Chris@261 638 if (desc != "") {
Chris@261 639
Chris@261 640 paint.save();
Chris@261 641
Chris@261 642 int tabStop =
Chris@261 643 paint.fontMetrics().width(tr("Some lengthy prefix:"));
Chris@261 644
Chris@261 645 QRect boundingRect =
Chris@261 646 paint.fontMetrics().boundingRect
Chris@261 647 (rect(),
Chris@261 648 Qt::AlignRight | Qt::AlignTop | Qt::TextExpandTabs,
Chris@261 649 desc, tabStop);
Chris@261 650
Chris@261 651 if (hasLightBackground()) {
Chris@261 652 paint.setPen(Qt::NoPen);
Chris@261 653 paint.setBrush(QColor(250, 250, 250, 200));
Chris@261 654 } else {
Chris@261 655 paint.setPen(Qt::NoPen);
Chris@261 656 paint.setBrush(QColor(50, 50, 50, 200));
Chris@261 657 }
Chris@261 658
Chris@261 659 int extra = paint.fontMetrics().descent();
Chris@261 660 paint.drawRect(width() - boundingRect.width() - 10 - extra,
Chris@261 661 10 - extra,
Chris@261 662 boundingRect.width() + 2 * extra,
Chris@261 663 boundingRect.height() + extra);
Chris@261 664
Chris@261 665 if (hasLightBackground()) {
Chris@261 666 paint.setPen(QColor(150, 20, 0));
Chris@261 667 } else {
Chris@261 668 paint.setPen(QColor(255, 150, 100));
Chris@261 669 }
Chris@261 670
Chris@261 671 QTextOption option;
Chris@261 672 option.setWrapMode(QTextOption::NoWrap);
Chris@261 673 option.setAlignment(Qt::AlignRight | Qt::AlignTop);
Chris@261 674 option.setTabStop(tabStop);
Chris@261 675 paint.drawText(QRectF(width() - boundingRect.width() - 10, 10,
Chris@261 676 boundingRect.width(),
Chris@261 677 boundingRect.height()),
Chris@261 678 desc,
Chris@261 679 option);
Chris@261 680
Chris@261 681 paint.restore();
Chris@261 682 }
Chris@261 683 }
Chris@258 684
Chris@261 685 void
Chris@277 686 Pane::drawCentreLine(int sampleRate, QPainter &paint, bool omitLine)
Chris@261 687 {
Chris@261 688 int fontHeight = paint.fontMetrics().height();
Chris@261 689 int fontAscent = paint.fontMetrics().ascent();
Chris@261 690
Chris@261 691 QColor c = QColor(0, 0, 0);
Chris@261 692 if (!hasLightBackground()) {
Chris@261 693 c = QColor(240, 240, 240);
Chris@261 694 }
Chris@277 695
Chris@261 696 paint.setPen(c);
Chris@274 697 int x = width() / 2;
Chris@277 698
Chris@277 699 if (!omitLine) {
Chris@277 700 paint.drawLine(x, 0, x, height() - 1);
Chris@277 701 paint.drawLine(x-1, 1, x+1, 1);
Chris@277 702 paint.drawLine(x-2, 0, x+2, 0);
Chris@277 703 paint.drawLine(x-1, height() - 2, x+1, height() - 2);
Chris@277 704 paint.drawLine(x-2, height() - 1, x+2, height() - 1);
Chris@277 705 }
Chris@261 706
Chris@261 707 paint.setPen(QColor(50, 50, 50));
Chris@261 708
Chris@261 709 int y = height() - fontHeight + fontAscent - 6;
Chris@261 710
Chris@261 711 LayerList::iterator vi = m_layers.end();
Chris@261 712
Chris@261 713 if (vi != m_layers.begin()) {
Chris@261 714
Chris@261 715 switch ((*--vi)->getPreferredFrameCountPosition()) {
Chris@258 716
Chris@261 717 case Layer::PositionTop:
Chris@261 718 y = fontAscent + 6;
Chris@261 719 break;
Chris@258 720
Chris@261 721 case Layer::PositionMiddle:
Chris@261 722 y = (height() - fontHeight) / 2
Chris@261 723 + fontAscent;
Chris@261 724 break;
Chris@127 725
Chris@261 726 case Layer::PositionBottom:
Chris@261 727 // y already set correctly
Chris@261 728 break;
Chris@127 729 }
Chris@127 730 }
Chris@127 731
Chris@261 732 if (m_manager && m_manager->shouldShowFrameCount()) {
Chris@261 733
Chris@261 734 if (sampleRate) {
Chris@127 735
Chris@261 736 QString text(QString::fromStdString
Chris@261 737 (RealTime::frame2RealTime
Chris@261 738 (m_centreFrame, sampleRate).toText(true)));
Chris@127 739
Chris@261 740 int tw = paint.fontMetrics().width(text);
Chris@261 741 int x = width()/2 - 4 - tw;
Chris@127 742
Chris@127 743 drawVisibleText(paint, x, y, text, OutlinedText);
Chris@127 744 }
Chris@261 745
Chris@261 746 QString text = QString("%1").arg(m_centreFrame);
Chris@261 747
Chris@261 748 int x = width()/2 + 4;
Chris@261 749
Chris@261 750 drawVisibleText(paint, x, y, text, OutlinedText);
Chris@261 751 }
Chris@261 752 }
Chris@127 753
Chris@261 754 void
Chris@326 755 Pane::drawAlignmentStatus(QRect r, QPainter &paint, const Model *model,
Chris@326 756 bool down)
Chris@320 757 {
Chris@320 758 const Model *reference = model->getAlignmentReference();
Chris@320 759 /*
Chris@320 760 if (!reference) {
Chris@320 761 std::cerr << "Pane[" << this << "]::drawAlignmentStatus: No reference" << std::endl;
Chris@320 762 } else if (reference == model) {
Chris@320 763 std::cerr << "Pane[" << this << "]::drawAlignmentStatus: This is the reference model" << std::endl;
Chris@320 764 } else {
Chris@320 765 std::cerr << "Pane[" << this << "]::drawAlignmentStatus: This is not the reference" << std::endl;
Chris@320 766 }
Chris@320 767 */
Chris@320 768 QString text;
Chris@320 769 int completion = 100;
Chris@320 770
Chris@320 771 if (reference == model) {
Chris@320 772 text = tr("Reference");
Chris@320 773 } else if (!reference) {
Chris@320 774 text = tr("Unaligned");
Chris@320 775 } else {
Chris@320 776 completion = model->getAlignmentCompletion();
Chris@320 777 if (completion == 0) {
Chris@320 778 text = tr("Unaligned");
Chris@320 779 } else if (completion < 100) {
Chris@320 780 text = tr("Aligning: %1%").arg(completion);
Chris@320 781 } else {
Chris@320 782 text = tr("Aligned");
Chris@320 783 }
Chris@320 784 }
Chris@320 785
Chris@320 786 paint.save();
Chris@320 787 QFont font(paint.font());
Chris@320 788 font.setBold(true);
Chris@320 789 paint.setFont(font);
Chris@326 790 if (completion < 100) paint.setBrush(Qt::red);
Chris@326 791
Chris@326 792 int y = 5;
Chris@326 793 if (down) y += paint.fontMetrics().height();
Chris@326 794 int w = paint.fontMetrics().width(text);
Chris@326 795 int h = paint.fontMetrics().height();
Chris@326 796 if (r.top() > h + y || r.left() > w + m_scaleWidth + 5) {
Chris@326 797 paint.restore();
Chris@326 798 return;
Chris@326 799 }
Chris@320 800
Chris@320 801 drawVisibleText(paint, m_scaleWidth + 5,
Chris@326 802 paint.fontMetrics().ascent() + y, text, OutlinedText);
Chris@320 803
Chris@320 804 paint.restore();
Chris@320 805 }
Chris@320 806
Chris@320 807 void
Chris@320 808 Pane::modelAlignmentCompletionChanged()
Chris@320 809 {
Chris@320 810 View::modelAlignmentCompletionChanged();
Chris@320 811 update(QRect(0, 0, 300, 100));
Chris@320 812 }
Chris@320 813
Chris@320 814 void
Chris@326 815 Pane::drawWorkTitle(QRect r, QPainter &paint, const Model *model)
Chris@326 816 {
Chris@326 817 QString title = model->getTitle();
Chris@326 818 QString maker = model->getMaker();
Chris@327 819 //std::cerr << "Pane::drawWorkTitle: title=\"" << title.toStdString()
Chris@327 820 //<< "\", maker=\"" << maker.toStdString() << "\"" << std::endl;
Chris@326 821 if (title == "") return;
Chris@326 822
Chris@326 823 QString text = title;
Chris@326 824 if (maker != "") {
Chris@326 825 text = tr("%1 - %2").arg(title).arg(maker);
Chris@326 826 }
Chris@326 827
Chris@326 828 paint.save();
Chris@326 829 QFont font(paint.font());
Chris@326 830 font.setItalic(true);
Chris@326 831 paint.setFont(font);
Chris@326 832
Chris@326 833 int y = 5;
Chris@326 834 int w = paint.fontMetrics().width(text);
Chris@326 835 int h = paint.fontMetrics().height();
Chris@326 836 if (r.top() > h + y || r.left() > w + m_scaleWidth + 5) {
Chris@326 837 paint.restore();
Chris@326 838 return;
Chris@326 839 }
Chris@326 840
Chris@326 841 drawVisibleText(paint, m_scaleWidth + 5,
Chris@326 842 paint.fontMetrics().ascent() + y, text, OutlinedText);
Chris@326 843
Chris@326 844 paint.restore();
Chris@326 845 }
Chris@326 846
Chris@326 847 void
Chris@261 848 Pane::drawLayerNames(QRect r, QPainter &paint)
Chris@261 849 {
Chris@261 850 int fontHeight = paint.fontMetrics().height();
Chris@261 851 int fontAscent = paint.fontMetrics().ascent();
Chris@127 852
Chris@300 853 int lly = height() - 6;
Chris@300 854 if (m_manager->getZoomWheelsEnabled()) {
Chris@300 855 lly -= 20;
Chris@300 856 }
Chris@300 857
Chris@300 858 if (r.y() + r.height() < lly - int(m_layers.size()) * fontHeight) {
Chris@261 859 return;
Chris@127 860 }
Chris@127 861
Chris@294 862 QStringList texts;
Chris@299 863 std::vector<QPixmap> pixmaps;
Chris@294 864 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@294 865 texts.push_back((*i)->getLayerPresentationName());
Chris@299 866 // std::cerr << "Pane " << this << ": Layer presentation name for " << *i << ": "
Chris@299 867 // << texts[texts.size()-1].toStdString() << std::endl;
Chris@299 868 pixmaps.push_back((*i)->getLayerPresentationPixmap
Chris@299 869 (QSize(fontAscent, fontAscent)));
Chris@294 870 }
Chris@127 871
Chris@294 872 int maxTextWidth = width() / 3;
Chris@294 873 texts = TextAbbrev::abbreviate(texts, paint.fontMetrics(), maxTextWidth);
Chris@294 874
Chris@261 875 int llx = width() - maxTextWidth - 5;
Chris@261 876 if (m_manager->getZoomWheelsEnabled()) {
Chris@261 877 llx -= 36;
Chris@261 878 }
Chris@261 879
Chris@300 880 if (r.x() + r.width() >= llx - fontAscent - 3) {
Chris@261 881
Chris@261 882 for (size_t i = 0; i < texts.size(); ++i) {
Chris@299 883
Chris@299 884 // std::cerr << "Pane "<< this << ": text " << i << ": " << texts[i].toStdString() << std::endl;
Chris@261 885
Chris@261 886 if (i + 1 == texts.size()) {
Chris@287 887 paint.setPen(getForeground());
Chris@261 888 }
Chris@261 889
Chris@261 890 drawVisibleText(paint, llx,
Chris@261 891 lly - fontHeight + fontAscent,
Chris@261 892 texts[i], OutlinedText);
Chris@299 893
Chris@299 894 if (!pixmaps[i].isNull()) {
Chris@299 895 paint.drawPixmap(llx - fontAscent - 3,
Chris@299 896 lly - fontHeight + (fontHeight-fontAscent)/2,
Chris@299 897 pixmaps[i]);
Chris@299 898 }
Chris@261 899
Chris@261 900 lly -= fontHeight;
Chris@261 901 }
Chris@261 902 }
Chris@261 903 }
Chris@127 904
Chris@261 905 void
Chris@261 906 Pane::drawEditingSelection(QPainter &paint)
Chris@261 907 {
Chris@261 908 int offset = m_mousePos.x() - m_clickPos.x();
Chris@261 909 int p0 = getXForFrame(m_editingSelection.getStartFrame()) + offset;
Chris@261 910 int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset;
Chris@261 911
Chris@261 912 if (m_editingSelectionEdge < 0) {
Chris@261 913 p1 = getXForFrame(m_editingSelection.getEndFrame());
Chris@261 914 } else if (m_editingSelectionEdge > 0) {
Chris@261 915 p0 = getXForFrame(m_editingSelection.getStartFrame());
Chris@127 916 }
Chris@127 917
Chris@261 918 paint.save();
Chris@287 919 paint.setPen(QPen(getForeground(), 2));
Chris@261 920
Chris@261 921 //!!! duplicating display policy with View::drawSelections
Chris@261 922
Chris@261 923 if (m_editingSelectionEdge < 0) {
Chris@261 924 paint.drawLine(p0, 1, p1, 1);
Chris@261 925 paint.drawLine(p0, 0, p0, height());
Chris@261 926 paint.drawLine(p0, height() - 1, p1, height() - 1);
Chris@261 927 } else if (m_editingSelectionEdge > 0) {
Chris@261 928 paint.drawLine(p0, 1, p1, 1);
Chris@261 929 paint.drawLine(p1, 0, p1, height());
Chris@261 930 paint.drawLine(p0, height() - 1, p1, height() - 1);
Chris@261 931 } else {
Chris@261 932 paint.setBrush(Qt::NoBrush);
Chris@261 933 paint.drawRect(p0, 1, p1 - p0, height() - 2);
Chris@261 934 }
Chris@261 935 paint.restore();
Chris@261 936 }
Chris@127 937
Chris@261 938 void
Chris@261 939 Pane::drawDurationAndRate(QRect r, const Model *waveformModel,
Chris@261 940 int sampleRate, QPainter &paint)
Chris@261 941 {
Chris@261 942 int fontHeight = paint.fontMetrics().height();
Chris@261 943 int fontAscent = paint.fontMetrics().ascent();
Chris@127 944
Chris@261 945 if (r.y() + r.height() < height() - fontHeight - 6) return;
Chris@127 946
Chris@261 947 size_t modelRate = waveformModel->getSampleRate();
Chris@301 948 size_t nativeRate = waveformModel->getNativeRate();
Chris@261 949 size_t playbackRate = m_manager->getPlaybackSampleRate();
Chris@261 950 size_t outputRate = m_manager->getOutputSampleRate();
Chris@261 951
Chris@261 952 QString srNote = "";
Chris@127 953
Chris@301 954 // Show (R) for waveform models that have been resampled or will
Chris@301 955 // be resampled on playback, and (X) for waveform models that will
Chris@301 956 // be played at the wrong rate because their rate differs from the
Chris@261 957 // current playback rate (which is not necessarily that of the
Chris@261 958 // main model).
Chris@127 959
Chris@261 960 if (playbackRate != 0) {
Chris@261 961 if (modelRate == playbackRate) {
Chris@301 962 if (modelRate != outputRate || modelRate != nativeRate) {
Chris@301 963 srNote = " " + tr("(R)");
Chris@301 964 }
Chris@261 965 } else {
Chris@261 966 srNote = " " + tr("(X)");
Chris@261 967 }
Chris@127 968 }
Chris@127 969
Chris@261 970 QString desc = tr("%1 / %2Hz%3")
Chris@261 971 .arg(RealTime::frame2RealTime(waveformModel->getEndFrame(),
Chris@261 972 sampleRate)
Chris@261 973 .toText(false).c_str())
Chris@301 974 .arg(nativeRate)
Chris@261 975 .arg(srNote);
Chris@261 976
Chris@384 977 int x = m_scaleWidth + 5;
Chris@384 978 int pbw = getProgressBarWidth();
Chris@384 979 if (x < pbw + 5) x = pbw + 5;
Chris@384 980
Chris@384 981 if (r.x() < x + paint.fontMetrics().width(desc)) {
Chris@384 982 drawVisibleText(paint, x,
Chris@261 983 height() - fontHeight + fontAscent - 6,
Chris@261 984 desc, OutlinedText);
Chris@261 985 }
Chris@127 986 }
Chris@127 987
Chris@227 988 bool
Chris@229 989 Pane::render(QPainter &paint, int xorigin, size_t f0, size_t f1)
Chris@227 990 {
Chris@229 991 if (!View::render(paint, xorigin + m_scaleWidth, f0, f1)) {
Chris@227 992 return false;
Chris@227 993 }
Chris@227 994
Chris@227 995 if (m_scaleWidth > 0) {
Chris@227 996
Chris@227 997 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
Chris@227 998 --vi;
Chris@227 999
Chris@227 1000 paint.save();
Chris@227 1001
Chris@287 1002 paint.setPen(getForeground());
Chris@287 1003 paint.setBrush(getBackground());
Chris@229 1004 paint.drawRect(xorigin, -1, m_scaleWidth, height()+1);
Chris@227 1005
Chris@227 1006 paint.setBrush(Qt::NoBrush);
Chris@227 1007 (*vi)->paintVerticalScale
Chris@229 1008 (this, paint, QRect(xorigin, 0, m_scaleWidth, height()));
Chris@227 1009
Chris@227 1010 paint.restore();
Chris@227 1011 break;
Chris@227 1012 }
Chris@227 1013 }
Chris@227 1014
Chris@227 1015 return true;
Chris@227 1016 }
Chris@227 1017
Chris@227 1018 QImage *
Chris@229 1019 Pane::toNewImage(size_t f0, size_t f1)
Chris@227 1020 {
Chris@227 1021 size_t x0 = f0 / getZoomLevel();
Chris@227 1022 size_t x1 = f1 / getZoomLevel();
Chris@227 1023
Chris@227 1024 QImage *image = new QImage(x1 - x0 + m_scaleWidth,
Chris@227 1025 height(), QImage::Format_RGB32);
Chris@227 1026
Chris@227 1027 int formerScaleWidth = m_scaleWidth;
Chris@227 1028
Chris@227 1029 if (m_manager && m_manager->shouldShowVerticalScale()) {
Chris@227 1030 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
Chris@227 1031 --vi;
Chris@227 1032 QPainter paint(image);
Chris@227 1033 m_scaleWidth = (*vi)->getVerticalScaleWidth(this, paint);
Chris@227 1034 break;
Chris@227 1035 }
Chris@227 1036 } else {
Chris@227 1037 m_scaleWidth = 0;
Chris@227 1038 }
Chris@227 1039
Chris@227 1040 if (m_scaleWidth != formerScaleWidth) {
Chris@227 1041 delete image;
Chris@227 1042 image = new QImage(x1 - x0 + m_scaleWidth,
Chris@227 1043 height(), QImage::Format_RGB32);
Chris@227 1044 }
Chris@227 1045
Chris@227 1046 QPainter *paint = new QPainter(image);
Chris@229 1047 if (!render(*paint, 0, f0, f1)) {
Chris@227 1048 delete paint;
Chris@227 1049 delete image;
Chris@227 1050 return 0;
Chris@227 1051 } else {
Chris@227 1052 delete paint;
Chris@227 1053 return image;
Chris@227 1054 }
Chris@227 1055 }
Chris@227 1056
Chris@229 1057 QSize
Chris@229 1058 Pane::getImageSize(size_t f0, size_t f1)
Chris@229 1059 {
Chris@229 1060 QSize s = View::getImageSize(f0, f1);
Chris@229 1061 QImage *image = new QImage(100, 100, QImage::Format_RGB32);
Chris@229 1062 QPainter paint(image);
Chris@229 1063
Chris@229 1064 int sw = 0;
Chris@229 1065 if (m_manager && m_manager->shouldShowVerticalScale()) {
Chris@229 1066 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
Chris@229 1067 --vi;
Chris@229 1068 QPainter paint(image);
Chris@229 1069 sw = (*vi)->getVerticalScaleWidth(this, paint);
Chris@229 1070 break;
Chris@229 1071 }
Chris@229 1072 }
Chris@229 1073
Chris@229 1074 return QSize(sw + s.width(), s.height());
Chris@229 1075 }
Chris@229 1076
Chris@222 1077 size_t
Chris@222 1078 Pane::getFirstVisibleFrame() const
Chris@222 1079 {
Chris@222 1080 long f0 = getFrameForX(m_scaleWidth);
Chris@222 1081 size_t f = View::getFirstVisibleFrame();
Chris@222 1082 if (f0 < 0 || f0 < long(f)) return f;
Chris@222 1083 return f0;
Chris@222 1084 }
Chris@222 1085
Chris@127 1086 Selection
Chris@127 1087 Pane::getSelectionAt(int x, bool &closeToLeftEdge, bool &closeToRightEdge) const
Chris@127 1088 {
Chris@127 1089 closeToLeftEdge = closeToRightEdge = false;
Chris@127 1090
Chris@127 1091 if (!m_manager) return Selection();
Chris@127 1092
Chris@127 1093 long testFrame = getFrameForX(x - 5);
Chris@127 1094 if (testFrame < 0) {
Chris@127 1095 testFrame = getFrameForX(x);
Chris@127 1096 if (testFrame < 0) return Selection();
Chris@127 1097 }
Chris@127 1098
Chris@127 1099 Selection selection = m_manager->getContainingSelection(testFrame, true);
Chris@127 1100 if (selection.isEmpty()) return selection;
Chris@127 1101
Chris@127 1102 int lx = getXForFrame(selection.getStartFrame());
Chris@127 1103 int rx = getXForFrame(selection.getEndFrame());
Chris@127 1104
Chris@127 1105 int fuzz = 2;
Chris@127 1106 if (x < lx - fuzz || x > rx + fuzz) return Selection();
Chris@127 1107
Chris@127 1108 int width = rx - lx;
Chris@127 1109 fuzz = 3;
Chris@127 1110 if (width < 12) fuzz = width / 4;
Chris@127 1111 if (fuzz < 1) fuzz = 1;
Chris@127 1112
Chris@127 1113 if (x < lx + fuzz) closeToLeftEdge = true;
Chris@127 1114 if (x > rx - fuzz) closeToRightEdge = true;
Chris@127 1115
Chris@127 1116 return selection;
Chris@127 1117 }
Chris@127 1118
Chris@174 1119 bool
Chris@174 1120 Pane::canTopLayerMoveVertical()
Chris@174 1121 {
Chris@174 1122 float vmin, vmax, dmin, dmax;
Chris@174 1123 if (!getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) return false;
Chris@174 1124 if (dmin <= vmin && dmax >= vmax) return false;
Chris@174 1125 return true;
Chris@174 1126 }
Chris@174 1127
Chris@174 1128 bool
Chris@174 1129 Pane::getTopLayerDisplayExtents(float &vmin, float &vmax,
Chris@188 1130 float &dmin, float &dmax,
Chris@188 1131 QString *unit)
Chris@174 1132 {
Chris@268 1133 Layer *layer = getTopLayer();
Chris@174 1134 if (!layer) return false;
Chris@174 1135 bool vlog;
Chris@174 1136 QString vunit;
Chris@188 1137 bool rv = (layer->getValueExtents(vmin, vmax, vlog, vunit) &&
Chris@188 1138 layer->getDisplayExtents(dmin, dmax));
Chris@188 1139 if (unit) *unit = vunit;
Chris@188 1140 return rv;
Chris@174 1141 }
Chris@174 1142
Chris@174 1143 bool
Chris@174 1144 Pane::setTopLayerDisplayExtents(float dmin, float dmax)
Chris@174 1145 {
Chris@268 1146 Layer *layer = getTopLayer();
Chris@174 1147 if (!layer) return false;
Chris@174 1148 return layer->setDisplayExtents(dmin, dmax);
Chris@174 1149 }
Chris@174 1150
Chris@127 1151 void
Chris@282 1152 Pane::registerShortcuts(KeyReference &kr)
Chris@282 1153 {
Chris@282 1154 kr.setCategory(tr("Zoom"));
Chris@282 1155 kr.registerAlternativeShortcut(tr("Zoom In"), tr("Wheel Up"));
Chris@282 1156 kr.registerAlternativeShortcut(tr("Zoom Out"), tr("Wheel Down"));
Chris@282 1157
Chris@282 1158 kr.setCategory(tr("General Pane Mouse Actions"));
Chris@282 1159
Chris@282 1160 kr.registerShortcut(tr("Zoom"), tr("Wheel"),
Chris@282 1161 tr("Zoom in or out in time axis"));
Chris@408 1162 kr.registerShortcut(tr("Scroll"), tr("Ctrl+Wheel"),
Chris@282 1163 tr("Scroll rapidly left or right in time axis"));
Chris@282 1164 kr.registerShortcut(tr("Zoom Vertically"), tr("Shift+Wheel"),
Chris@282 1165 tr("Zoom in or out in the vertical axis"));
Chris@282 1166 kr.registerShortcut(tr("Scroll Vertically"), tr("Alt+Wheel"),
Chris@282 1167 tr("Scroll up or down in the vertical axis"));
Chris@282 1168 kr.registerShortcut(tr("Navigate"), tr("Middle"),
Chris@282 1169 tr("Click middle button and drag to navigate with any tool"));
Chris@282 1170 kr.registerShortcut(tr("Relocate"), tr("Double-Click Middle"),
Chris@282 1171 tr("Double-click middle button to relocate with any tool"));
Chris@282 1172 kr.registerShortcut(tr("Menu"), tr("Right"),
Chris@282 1173 tr("Show pane context menu"));
Chris@282 1174
Chris@282 1175 kr.setCategory(tr("Navigate Tool Mouse Actions"));
Chris@282 1176
Chris@282 1177 kr.registerShortcut(tr("Navigate"), tr("Left"),
Chris@282 1178 tr("Click left button and drag to move around"));
Chris@282 1179 kr.registerShortcut(tr("Zoom to Area"), tr("Shift+Left"),
Chris@282 1180 tr("Shift-click left button and drag to zoom to a rectangular area"));
Chris@282 1181 kr.registerShortcut(tr("Relocate"), tr("Double-Click Left"),
Chris@282 1182 tr("Double-click left button to jump to clicked location"));
Chris@282 1183 kr.registerShortcut(tr("Edit"), tr("Double-Click Left"),
Chris@282 1184 tr("Double-click left button on an item to edit it"));
Chris@282 1185
Chris@282 1186 kr.setCategory(tr("Select Tool Mouse Actions"));
Chris@282 1187 kr.registerShortcut(tr("Select"), tr("Left"),
Chris@282 1188 tr("Click left button and drag to select region; drag region edge to resize"));
Chris@282 1189 kr.registerShortcut(tr("Multi Select"), tr("Ctrl+Left"),
Chris@282 1190 tr("Ctrl-click left button and drag to select an additional region"));
Chris@283 1191 kr.registerShortcut(tr("Fine Select"), tr("Shift+Left"),
Chris@283 1192 tr("Shift-click left button and drag to select without snapping to items or grid"));
Chris@282 1193
Chris@282 1194 kr.setCategory(tr("Edit Tool Mouse Actions"));
Chris@282 1195 kr.registerShortcut(tr("Move"), tr("Left"),
Chris@282 1196 tr("Click left button on an item or selected region and drag to move"));
Chris@282 1197 kr.registerShortcut(tr("Edit"), tr("Double-Click Left"),
Chris@282 1198 tr("Double-click left button on an item to edit it"));
Chris@282 1199
Chris@282 1200 kr.setCategory(tr("Draw Tool Mouse Actions"));
Chris@282 1201 kr.registerShortcut(tr("Draw"), tr("Left"),
Chris@282 1202 tr("Click left button and drag to create new item"));
Chris@282 1203
Chris@282 1204 kr.setCategory(tr("Measure Tool Mouse Actions"));
Chris@282 1205 kr.registerShortcut(tr("Measure Area"), tr("Left"),
Chris@282 1206 tr("Click left button and drag to measure a rectangular area"));
Chris@282 1207 kr.registerShortcut(tr("Measure Item"), tr("Double-Click Left"),
Chris@282 1208 tr("Click left button and drag to measure extents of an item or shape"));
Chris@283 1209 kr.registerShortcut(tr("Zoom to Area"), tr("Shift+Left"),
Chris@283 1210 tr("Shift-click left button and drag to zoom to a rectangular area"));
Chris@282 1211 }
Chris@282 1212
Chris@282 1213 void
Chris@127 1214 Pane::mousePressEvent(QMouseEvent *e)
Chris@127 1215 {
Chris@127 1216 if (e->buttons() & Qt::RightButton) {
Chris@189 1217 emit contextHelpChanged("");
Chris@127 1218 emit rightButtonMenuRequested(mapToGlobal(e->pos()));
Chris@127 1219 return;
Chris@127 1220 }
Chris@127 1221
Chris@343 1222 // std::cerr << "mousePressEvent" << std::endl;
Chris@341 1223
Chris@127 1224 m_clickPos = e->pos();
Chris@262 1225 m_mousePos = m_clickPos;
Chris@127 1226 m_clickedInRange = true;
Chris@127 1227 m_editingSelection = Selection();
Chris@127 1228 m_editingSelectionEdge = 0;
Chris@127 1229 m_shiftPressed = (e->modifiers() & Qt::ShiftModifier);
Chris@127 1230 m_ctrlPressed = (e->modifiers() & Qt::ControlModifier);
Chris@150 1231 m_dragMode = UnresolvedDrag;
Chris@127 1232
Chris@127 1233 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@127 1234 if (m_manager) mode = m_manager->getToolMode();
Chris@127 1235
Chris@127 1236 m_navigating = false;
Chris@343 1237 m_resizing = false;
Chris@343 1238 m_editing = false;
Chris@343 1239 m_releasing = false;
Chris@127 1240
Chris@283 1241 if (mode == ViewManager::NavigateMode ||
Chris@283 1242 (e->buttons() & Qt::MidButton) ||
Chris@283 1243 (mode == ViewManager::MeasureMode &&
Chris@283 1244 (e->buttons() & Qt::LeftButton) && m_shiftPressed)) {
Chris@127 1245
Chris@127 1246 if (mode != ViewManager::NavigateMode) {
Chris@127 1247 setCursor(Qt::PointingHandCursor);
Chris@127 1248 }
Chris@127 1249
Chris@127 1250 m_navigating = true;
Chris@127 1251 m_dragCentreFrame = m_centreFrame;
Chris@136 1252 m_dragStartMinValue = 0;
Chris@174 1253
Chris@174 1254 float vmin, vmax, dmin, dmax;
Chris@174 1255 if (getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) {
Chris@174 1256 m_dragStartMinValue = dmin;
Chris@136 1257 }
Chris@136 1258
Chris@127 1259 } else if (mode == ViewManager::SelectMode) {
Chris@127 1260
Chris@217 1261 if (!hasTopLayerTimeXAxis()) return;
Chris@217 1262
Chris@127 1263 bool closeToLeft = false, closeToRight = false;
Chris@127 1264 Selection selection = getSelectionAt(e->x(), closeToLeft, closeToRight);
Chris@127 1265
Chris@127 1266 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) {
Chris@127 1267
Chris@127 1268 m_manager->removeSelection(selection);
Chris@127 1269
Chris@127 1270 if (closeToLeft) {
Chris@127 1271 m_selectionStartFrame = selection.getEndFrame();
Chris@127 1272 } else {
Chris@127 1273 m_selectionStartFrame = selection.getStartFrame();
Chris@127 1274 }
Chris@127 1275
Chris@127 1276 m_manager->setInProgressSelection(selection, false);
Chris@127 1277 m_resizing = true;
Chris@127 1278
Chris@127 1279 } else {
Chris@127 1280
Chris@127 1281 int mouseFrame = getFrameForX(e->x());
Chris@127 1282 size_t resolution = 1;
Chris@127 1283 int snapFrame = mouseFrame;
Chris@127 1284
Chris@127 1285 Layer *layer = getSelectedLayer();
Chris@127 1286 if (layer && !m_shiftPressed) {
Chris@127 1287 layer->snapToFeatureFrame(this, snapFrame,
Chris@127 1288 resolution, Layer::SnapLeft);
Chris@127 1289 }
Chris@127 1290
Chris@127 1291 if (snapFrame < 0) snapFrame = 0;
Chris@127 1292 m_selectionStartFrame = snapFrame;
Chris@127 1293 if (m_manager) {
Chris@333 1294 m_manager->setInProgressSelection
Chris@333 1295 (Selection(alignToReference(snapFrame),
Chris@333 1296 alignToReference(snapFrame + resolution)),
Chris@333 1297 !m_ctrlPressed);
Chris@127 1298 }
Chris@127 1299
Chris@127 1300 m_resizing = false;
Chris@127 1301 }
Chris@127 1302
Chris@127 1303 update();
Chris@127 1304
Chris@127 1305 } else if (mode == ViewManager::DrawMode) {
Chris@127 1306
Chris@127 1307 Layer *layer = getSelectedLayer();
Chris@127 1308 if (layer && layer->isLayerEditable()) {
Chris@127 1309 layer->drawStart(this, e);
Chris@127 1310 }
Chris@127 1311
Chris@335 1312 } else if (mode == ViewManager::EraseMode) {
Chris@335 1313
Chris@335 1314 Layer *layer = getSelectedLayer();
Chris@335 1315 if (layer && layer->isLayerEditable()) {
Chris@335 1316 layer->eraseStart(this, e);
Chris@335 1317 }
Chris@335 1318
Chris@127 1319 } else if (mode == ViewManager::EditMode) {
Chris@127 1320
Chris@343 1321 // Do nothing here -- we'll do it in mouseMoveEvent when the
Chris@343 1322 // drag threshold has been passed
Chris@262 1323
Chris@262 1324 } else if (mode == ViewManager::MeasureMode) {
Chris@262 1325
Chris@268 1326 Layer *layer = getTopLayer();
Chris@267 1327 if (layer) layer->measureStart(this, e);
Chris@262 1328 update();
Chris@127 1329 }
Chris@127 1330
Chris@127 1331 emit paneInteractedWith();
Chris@127 1332 }
Chris@127 1333
Chris@127 1334 void
Chris@127 1335 Pane::mouseReleaseEvent(QMouseEvent *e)
Chris@127 1336 {
Chris@127 1337 if (e->buttons() & Qt::RightButton) {
Chris@127 1338 return;
Chris@127 1339 }
Chris@127 1340
Chris@343 1341 // std::cerr << "mouseReleaseEvent" << std::endl;
Chris@341 1342
Chris@127 1343 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@127 1344 if (m_manager) mode = m_manager->getToolMode();
Chris@127 1345
Chris@343 1346 m_releasing = true;
Chris@343 1347
Chris@127 1348 if (m_clickedInRange) {
Chris@127 1349 mouseMoveEvent(e);
Chris@127 1350 }
Chris@127 1351
Chris@127 1352 if (m_navigating || mode == ViewManager::NavigateMode) {
Chris@127 1353
Chris@127 1354 m_navigating = false;
Chris@127 1355
Chris@127 1356 if (mode != ViewManager::NavigateMode) {
Chris@127 1357 // restore cursor
Chris@127 1358 toolModeChanged();
Chris@127 1359 }
Chris@127 1360
Chris@127 1361 if (m_shiftPressed) {
Chris@127 1362
Chris@127 1363 int x0 = std::min(m_clickPos.x(), m_mousePos.x());
Chris@127 1364 int x1 = std::max(m_clickPos.x(), m_mousePos.x());
Chris@127 1365
Chris@127 1366 int y0 = std::min(m_clickPos.y(), m_mousePos.y());
Chris@127 1367 int y1 = std::max(m_clickPos.y(), m_mousePos.y());
Chris@127 1368
Chris@174 1369 zoomToRegion(x0, y0, x1, y1);
Chris@127 1370 }
Chris@127 1371
Chris@127 1372 } else if (mode == ViewManager::SelectMode) {
Chris@127 1373
Chris@343 1374 if (!hasTopLayerTimeXAxis()) {
Chris@343 1375 m_releasing = false;
Chris@343 1376 return;
Chris@343 1377 }
Chris@217 1378
Chris@127 1379 if (m_manager && m_manager->haveInProgressSelection()) {
Chris@127 1380
Chris@127 1381 bool exclusive;
Chris@127 1382 Selection selection = m_manager->getInProgressSelection(exclusive);
Chris@127 1383
Chris@127 1384 if (selection.getEndFrame() < selection.getStartFrame() + 2) {
Chris@127 1385 selection = Selection();
Chris@127 1386 }
Chris@127 1387
Chris@127 1388 m_manager->clearInProgressSelection();
Chris@127 1389
Chris@127 1390 if (exclusive) {
Chris@127 1391 m_manager->setSelection(selection);
Chris@127 1392 } else {
Chris@127 1393 m_manager->addSelection(selection);
Chris@127 1394 }
Chris@127 1395 }
Chris@127 1396
Chris@127 1397 update();
Chris@127 1398
Chris@127 1399 } else if (mode == ViewManager::DrawMode) {
Chris@127 1400
Chris@127 1401 Layer *layer = getSelectedLayer();
Chris@127 1402 if (layer && layer->isLayerEditable()) {
Chris@127 1403 layer->drawEnd(this, e);
Chris@127 1404 update();
Chris@127 1405 }
Chris@127 1406
Chris@335 1407 } else if (mode == ViewManager::EraseMode) {
Chris@335 1408
Chris@335 1409 Layer *layer = getSelectedLayer();
Chris@335 1410 if (layer && layer->isLayerEditable()) {
Chris@335 1411 layer->eraseEnd(this, e);
Chris@335 1412 update();
Chris@335 1413 }
Chris@335 1414
Chris@127 1415 } else if (mode == ViewManager::EditMode) {
Chris@127 1416
Chris@343 1417 if (m_editing) {
Chris@343 1418 if (!editSelectionEnd(e)) {
Chris@343 1419 Layer *layer = getSelectedLayer();
Chris@343 1420 if (layer && layer->isLayerEditable()) {
Chris@343 1421 layer->editEnd(this, e);
Chris@343 1422 update();
Chris@343 1423 }
Chris@343 1424 }
Chris@343 1425 }
Chris@262 1426
Chris@262 1427 } else if (mode == ViewManager::MeasureMode) {
Chris@262 1428
Chris@268 1429 Layer *layer = getTopLayer();
Chris@267 1430 if (layer) layer->measureEnd(this, e);
Chris@267 1431 if (m_measureCursor1) setCursor(*m_measureCursor1);
Chris@267 1432 update();
Chris@127 1433 }
Chris@127 1434
Chris@127 1435 m_clickedInRange = false;
Chris@343 1436 m_releasing = false;
Chris@127 1437
Chris@127 1438 emit paneInteractedWith();
Chris@127 1439 }
Chris@127 1440
Chris@127 1441 void
Chris@127 1442 Pane::mouseMoveEvent(QMouseEvent *e)
Chris@127 1443 {
Chris@127 1444 if (e->buttons() & Qt::RightButton) {
Chris@127 1445 return;
Chris@127 1446 }
Chris@127 1447
Chris@343 1448 // std::cerr << "mouseMoveEvent" << std::endl;
Chris@341 1449
Chris@189 1450 updateContextHelp(&e->pos());
Chris@189 1451
Chris@343 1452 if (m_navigating && m_clickedInRange && !m_releasing) {
Chris@343 1453
Chris@343 1454 // if no buttons pressed, and not called from
Chris@343 1455 // mouseReleaseEvent, we want to reset clicked-ness (to avoid
Chris@343 1456 // annoying continual drags when we moved the mouse outside
Chris@343 1457 // the window after pressing button first time).
Chris@343 1458
Chris@343 1459 if (!(e->buttons() & Qt::LeftButton) &&
Chris@343 1460 !(e->buttons() & Qt::MidButton)) {
Chris@343 1461 m_clickedInRange = false;
Chris@343 1462 return;
Chris@343 1463 }
Chris@343 1464 }
Chris@343 1465
Chris@127 1466 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@127 1467 if (m_manager) mode = m_manager->getToolMode();
Chris@127 1468
Chris@127 1469 QPoint prevPoint = m_identifyPoint;
Chris@127 1470 m_identifyPoint = e->pos();
Chris@127 1471
Chris@127 1472 if (!m_clickedInRange) {
Chris@127 1473
Chris@217 1474 if (mode == ViewManager::SelectMode && hasTopLayerTimeXAxis()) {
Chris@127 1475 bool closeToLeft = false, closeToRight = false;
Chris@127 1476 getSelectionAt(e->x(), closeToLeft, closeToRight);
Chris@127 1477 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) {
Chris@127 1478 setCursor(Qt::SizeHorCursor);
Chris@127 1479 } else {
Chris@127 1480 setCursor(Qt::ArrowCursor);
Chris@127 1481 }
Chris@127 1482 }
Chris@127 1483
Chris@127 1484 if (!m_manager->isPlaying()) {
Chris@127 1485
Chris@272 1486 bool updating = false;
Chris@272 1487
Chris@326 1488 if (getSelectedLayer() &&
Chris@326 1489 m_manager->shouldIlluminateLocalFeatures()) {
Chris@127 1490
Chris@174 1491 bool previouslyIdentifying = m_identifyFeatures;
Chris@174 1492 m_identifyFeatures = true;
Chris@174 1493
Chris@174 1494 if (m_identifyFeatures != previouslyIdentifying ||
Chris@174 1495 m_identifyPoint != prevPoint) {
Chris@174 1496 update();
Chris@272 1497 updating = true;
Chris@272 1498 }
Chris@272 1499 }
Chris@272 1500
Chris@272 1501 if (!updating && mode == ViewManager::MeasureMode &&
Chris@272 1502 m_manager && !m_manager->isPlaying()) {
Chris@272 1503
Chris@272 1504 Layer *layer = getTopLayer();
Chris@272 1505 if (layer && layer->nearestMeasurementRectChanged
Chris@272 1506 (this, prevPoint, m_identifyPoint)) {
Chris@272 1507 update();
Chris@174 1508 }
Chris@174 1509 }
Chris@127 1510 }
Chris@127 1511
Chris@127 1512 return;
Chris@127 1513 }
Chris@127 1514
Chris@127 1515 if (m_navigating || mode == ViewManager::NavigateMode) {
Chris@127 1516
Chris@127 1517 if (m_shiftPressed) {
Chris@127 1518
Chris@127 1519 m_mousePos = e->pos();
Chris@127 1520 update();
Chris@127 1521
Chris@127 1522 } else {
Chris@127 1523
Chris@174 1524 dragTopLayer(e);
Chris@150 1525 }
Chris@127 1526
Chris@127 1527 } else if (mode == ViewManager::SelectMode) {
Chris@127 1528
Chris@217 1529 if (!hasTopLayerTimeXAxis()) return;
Chris@217 1530
Chris@174 1531 dragExtendSelection(e);
Chris@127 1532
Chris@127 1533 } else if (mode == ViewManager::DrawMode) {
Chris@127 1534
Chris@127 1535 Layer *layer = getSelectedLayer();
Chris@127 1536 if (layer && layer->isLayerEditable()) {
Chris@127 1537 layer->drawDrag(this, e);
Chris@127 1538 }
Chris@127 1539
Chris@335 1540 } else if (mode == ViewManager::EraseMode) {
Chris@335 1541
Chris@335 1542 Layer *layer = getSelectedLayer();
Chris@335 1543 if (layer && layer->isLayerEditable()) {
Chris@335 1544 layer->eraseDrag(this, e);
Chris@335 1545 }
Chris@335 1546
Chris@127 1547 } else if (mode == ViewManager::EditMode) {
Chris@127 1548
Chris@343 1549 if (m_editing) {
Chris@343 1550 if (!editSelectionDrag(e)) {
Chris@343 1551 Layer *layer = getSelectedLayer();
Chris@343 1552 if (layer && layer->isLayerEditable()) {
Chris@343 1553 layer->editDrag(this, e);
Chris@343 1554 }
Chris@343 1555 }
Chris@343 1556 }
Chris@343 1557
Chris@343 1558 if (!m_editing) {
Chris@343 1559
Chris@387 1560 bool resist = true;
Chris@387 1561
Chris@387 1562 if ((e->modifiers() & Qt::ShiftModifier)) {
Chris@387 1563 m_shiftPressed = true;
Chris@387 1564 // ... but don't set it false if shift has been
Chris@387 1565 // released -- we want the state when we started
Chris@387 1566 // dragging to be used most of the time
Chris@387 1567 }
Chris@387 1568
Chris@387 1569 if (m_shiftPressed) resist = false;
Chris@387 1570
Chris@343 1571 DragMode newDragMode = updateDragMode
Chris@343 1572 (m_dragMode,
Chris@343 1573 m_clickPos,
Chris@343 1574 e->pos(),
Chris@387 1575 true, // can move horiz
Chris@387 1576 true, // can move vert
Chris@387 1577 resist, // resist horiz
Chris@387 1578 resist); // resist vert
Chris@343 1579
Chris@343 1580 if (newDragMode != UnresolvedDrag) {
Chris@343 1581
Chris@343 1582 m_editing = true;
Chris@343 1583
Chris@343 1584 QMouseEvent clickEvent(QEvent::MouseButtonPress,
Chris@343 1585 m_clickPos,
Chris@343 1586 Qt::NoButton,
Chris@343 1587 e->buttons(),
Chris@343 1588 e->modifiers());
Chris@343 1589
Chris@343 1590 if (!editSelectionStart(&clickEvent)) {
Chris@343 1591 Layer *layer = getSelectedLayer();
Chris@343 1592 if (layer && layer->isLayerEditable()) {
Chris@343 1593 layer->editStart(this, &clickEvent);
Chris@343 1594 }
Chris@343 1595 }
Chris@343 1596 }
Chris@343 1597 }
Chris@259 1598
Chris@259 1599 } else if (mode == ViewManager::MeasureMode) {
Chris@259 1600
Chris@267 1601 if (m_measureCursor2) setCursor(*m_measureCursor2);
Chris@266 1602
Chris@268 1603 Layer *layer = getTopLayer();
Chris@290 1604 if (layer) {
Chris@290 1605 layer->measureDrag(this, e);
Chris@290 1606 if (layer->hasTimeXAxis()) edgeScrollMaybe(e->x());
Chris@290 1607 }
Chris@267 1608
Chris@267 1609 update();
Chris@127 1610 }
Chris@127 1611 }
Chris@127 1612
Chris@127 1613 void
Chris@174 1614 Pane::zoomToRegion(int x0, int y0, int x1, int y1)
Chris@174 1615 {
Chris@174 1616 int w = x1 - x0;
Chris@174 1617
Chris@174 1618 long newStartFrame = getFrameForX(x0);
Chris@174 1619
Chris@174 1620 long visibleFrames = getEndFrame() - getStartFrame();
Chris@174 1621 if (newStartFrame <= -visibleFrames) {
Chris@174 1622 newStartFrame = -visibleFrames + 1;
Chris@174 1623 }
Chris@174 1624
Chris@174 1625 if (newStartFrame >= long(getModelsEndFrame())) {
Chris@174 1626 newStartFrame = getModelsEndFrame() - 1;
Chris@174 1627 }
Chris@174 1628
Chris@174 1629 float ratio = float(w) / float(width());
Chris@174 1630 // std::cerr << "ratio: " << ratio << std::endl;
Chris@174 1631 size_t newZoomLevel = (size_t)nearbyint(m_zoomLevel * ratio);
Chris@174 1632 if (newZoomLevel < 1) newZoomLevel = 1;
Chris@174 1633
Chris@174 1634 // std::cerr << "start: " << m_startFrame << ", level " << m_zoomLevel << std::endl;
Chris@174 1635 setZoomLevel(getZoomConstraintBlockSize(newZoomLevel));
Chris@174 1636 setStartFrame(newStartFrame);
Chris@174 1637
Chris@174 1638 QString unit;
Chris@174 1639 float min, max;
Chris@174 1640 bool log;
Chris@174 1641 Layer *layer = 0;
Chris@174 1642 for (LayerList::const_iterator i = m_layers.begin();
Chris@174 1643 i != m_layers.end(); ++i) {
Chris@174 1644 if ((*i)->getValueExtents(min, max, log, unit) &&
Chris@174 1645 (*i)->getDisplayExtents(min, max)) {
Chris@174 1646 layer = *i;
Chris@174 1647 break;
Chris@174 1648 }
Chris@174 1649 }
Chris@174 1650
Chris@174 1651 if (layer) {
Chris@174 1652 if (log) {
Chris@174 1653 min = (min < 0.0) ? -log10f(-min) : (min == 0.0) ? 0.0 : log10f(min);
Chris@174 1654 max = (max < 0.0) ? -log10f(-max) : (max == 0.0) ? 0.0 : log10f(max);
Chris@174 1655 }
Chris@174 1656 float rmin = min + ((max - min) * (height() - y1)) / height();
Chris@174 1657 float rmax = min + ((max - min) * (height() - y0)) / height();
Chris@174 1658 std::cerr << "min: " << min << ", max: " << max << ", y0: " << y0 << ", y1: " << y1 << ", h: " << height() << ", rmin: " << rmin << ", rmax: " << rmax << std::endl;
Chris@174 1659 if (log) {
Chris@174 1660 rmin = powf(10, rmin);
Chris@174 1661 rmax = powf(10, rmax);
Chris@174 1662 }
Chris@174 1663 std::cerr << "finally: rmin: " << rmin << ", rmax: " << rmax << " " << unit.toStdString() << std::endl;
Chris@174 1664
Chris@174 1665 layer->setDisplayExtents(rmin, rmax);
Chris@174 1666 updateVerticalPanner();
Chris@174 1667 }
Chris@174 1668 }
Chris@174 1669
Chris@174 1670 void
Chris@174 1671 Pane::dragTopLayer(QMouseEvent *e)
Chris@174 1672 {
Chris@174 1673 // We need to avoid making it too easy to drag both
Chris@174 1674 // horizontally and vertically, in the case where the
Chris@174 1675 // mouse is moved "mostly" in horizontal or vertical axis
Chris@174 1676 // with only a small variation in the other axis. This is
Chris@174 1677 // particularly important during playback (when we want to
Chris@174 1678 // avoid small horizontal motions) or in slow refresh
Chris@174 1679 // layers like spectrogram (when we want to avoid small
Chris@174 1680 // vertical motions).
Chris@174 1681 //
Chris@174 1682 // To this end we have horizontal and vertical thresholds
Chris@174 1683 // and a series of states: unresolved, horizontally or
Chris@174 1684 // vertically constrained, free.
Chris@174 1685 //
Chris@174 1686 // When the mouse first moves, we're unresolved: we
Chris@174 1687 // restrict ourselves to whichever direction seems safest,
Chris@174 1688 // until the mouse has passed a small threshold distance
Chris@174 1689 // from the click point. Then we lock in to one of the
Chris@174 1690 // constrained modes, based on which axis that distance
Chris@174 1691 // was measured in first. Finally, if it turns out we've
Chris@174 1692 // also moved more than a certain larger distance in the
Chris@174 1693 // other direction as well, we may switch into free mode.
Chris@174 1694 //
Chris@174 1695 // If the top layer is incapable of being dragged
Chris@174 1696 // vertically, the logic is short circuited.
Chris@174 1697
Chris@343 1698 m_dragMode = updateDragMode
Chris@343 1699 (m_dragMode,
Chris@343 1700 m_clickPos,
Chris@343 1701 e->pos(),
Chris@343 1702 true, // can move horiz
Chris@343 1703 canTopLayerMoveVertical(), // can move vert
Chris@343 1704 canTopLayerMoveVertical() || (m_manager && m_manager->isPlaying()), // resist horiz
Chris@343 1705 !(m_manager && m_manager->isPlaying())); // resist vert
Chris@174 1706
Chris@343 1707 if (m_dragMode == HorizontalDrag ||
Chris@343 1708 m_dragMode == FreeDrag) {
Chris@174 1709
Chris@174 1710 long frameOff = getFrameForX(e->x()) - getFrameForX(m_clickPos.x());
Chris@174 1711
Chris@174 1712 size_t newCentreFrame = m_dragCentreFrame;
Chris@174 1713
Chris@174 1714 if (frameOff < 0) {
Chris@174 1715 newCentreFrame -= frameOff;
Chris@174 1716 } else if (newCentreFrame >= size_t(frameOff)) {
Chris@174 1717 newCentreFrame -= frameOff;
Chris@174 1718 } else {
Chris@174 1719 newCentreFrame = 0;
Chris@174 1720 }
Chris@363 1721
Chris@363 1722 #ifdef DEBUG_PANE
Chris@339 1723 std::cerr << "Pane::dragTopLayer: newCentreFrame = " << newCentreFrame <<
Chris@339 1724 ", models end frame = " << getModelsEndFrame() << std::endl;
Chris@363 1725 #endif
Chris@339 1726
Chris@174 1727 if (newCentreFrame >= getModelsEndFrame()) {
Chris@174 1728 newCentreFrame = getModelsEndFrame();
Chris@174 1729 if (newCentreFrame > 0) --newCentreFrame;
Chris@174 1730 }
Chris@174 1731
Chris@174 1732 if (getXForFrame(m_centreFrame) != getXForFrame(newCentreFrame)) {
Chris@174 1733 setCentreFrame(newCentreFrame);
Chris@174 1734 }
Chris@174 1735 }
Chris@174 1736
Chris@343 1737 if (m_dragMode == VerticalDrag ||
Chris@343 1738 m_dragMode == FreeDrag) {
Chris@174 1739
Chris@174 1740 float vmin = 0.f, vmax = 0.f;
Chris@174 1741 float dmin = 0.f, dmax = 0.f;
Chris@174 1742
Chris@174 1743 if (getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) {
Chris@174 1744
Chris@248 1745 // std::cerr << "ydiff = " << ydiff << std::endl;
Chris@174 1746
Chris@343 1747 int ydiff = e->y() - m_clickPos.y();
Chris@174 1748 float perpix = (dmax - dmin) / height();
Chris@174 1749 float valdiff = ydiff * perpix;
Chris@248 1750 // std::cerr << "valdiff = " << valdiff << std::endl;
Chris@174 1751
Chris@343 1752 if (m_dragMode == UnresolvedDrag && ydiff != 0) {
Chris@343 1753 m_dragMode = VerticalDrag;
Chris@343 1754 }
Chris@343 1755
Chris@174 1756 float newmin = m_dragStartMinValue + valdiff;
Chris@174 1757 float newmax = m_dragStartMinValue + (dmax - dmin) + valdiff;
Chris@174 1758 if (newmin < vmin) {
Chris@174 1759 newmax += vmin - newmin;
Chris@174 1760 newmin += vmin - newmin;
Chris@174 1761 }
Chris@174 1762 if (newmax > vmax) {
Chris@174 1763 newmin -= newmax - vmax;
Chris@174 1764 newmax -= newmax - vmax;
Chris@174 1765 }
Chris@248 1766 // std::cerr << "(" << dmin << ", " << dmax << ") -> ("
Chris@248 1767 // << newmin << ", " << newmax << ") (drag start " << m_dragStartMinValue << ")" << std::endl;
Chris@174 1768
Chris@174 1769 setTopLayerDisplayExtents(newmin, newmax);
Chris@174 1770 updateVerticalPanner();
Chris@174 1771 }
Chris@174 1772 }
Chris@174 1773 }
Chris@174 1774
Chris@343 1775 Pane::DragMode
Chris@343 1776 Pane::updateDragMode(DragMode dragMode,
Chris@343 1777 QPoint origin,
Chris@343 1778 QPoint point,
Chris@343 1779 bool canMoveHorizontal,
Chris@343 1780 bool canMoveVertical,
Chris@343 1781 bool resistHorizontal,
Chris@343 1782 bool resistVertical)
Chris@343 1783 {
Chris@343 1784 int xdiff = point.x() - origin.x();
Chris@343 1785 int ydiff = point.y() - origin.y();
Chris@343 1786
Chris@343 1787 int smallThreshold = 10, bigThreshold = 80;
Chris@343 1788
Chris@343 1789 // std::cerr << "Pane::updateDragMode: xdiff = " << xdiff << ", ydiff = "
Chris@343 1790 // << ydiff << ", canMoveVertical = " << canMoveVertical << ", drag mode = " << m_dragMode << std::endl;
Chris@343 1791
Chris@343 1792 if (dragMode == UnresolvedDrag) {
Chris@343 1793
Chris@343 1794 if (abs(ydiff) > smallThreshold &&
Chris@343 1795 abs(ydiff) > abs(xdiff) * 2 &&
Chris@343 1796 canMoveVertical) {
Chris@343 1797 // std::cerr << "Pane::updateDragMode: passed vertical threshold" << std::endl;
Chris@343 1798 dragMode = VerticalDrag;
Chris@343 1799 } else if (abs(xdiff) > smallThreshold &&
Chris@343 1800 abs(xdiff) > abs(ydiff) * 2 &&
Chris@343 1801 canMoveHorizontal) {
Chris@343 1802 // std::cerr << "Pane::updateDragMode: passed horizontal threshold" << std::endl;
Chris@343 1803 dragMode = HorizontalDrag;
Chris@343 1804 } else if (abs(xdiff) > smallThreshold &&
Chris@343 1805 abs(ydiff) > smallThreshold &&
Chris@343 1806 canMoveVertical &&
Chris@343 1807 canMoveHorizontal) {
Chris@343 1808 // std::cerr << "Pane::updateDragMode: passed both thresholds" << std::endl;
Chris@343 1809 dragMode = FreeDrag;
Chris@343 1810 }
Chris@343 1811 }
Chris@343 1812
Chris@343 1813 if (dragMode == VerticalDrag && canMoveHorizontal) {
Chris@343 1814 if (abs(xdiff) > bigThreshold) dragMode = FreeDrag;
Chris@343 1815 }
Chris@343 1816
Chris@343 1817 if (dragMode == HorizontalDrag && canMoveVertical) {
Chris@343 1818 if (abs(ydiff) > bigThreshold) dragMode = FreeDrag;
Chris@343 1819 }
Chris@343 1820
Chris@343 1821 if (dragMode == UnresolvedDrag) {
Chris@343 1822 if (!resistHorizontal && xdiff != 0) {
Chris@343 1823 dragMode = HorizontalDrag;
Chris@343 1824 }
Chris@343 1825 if (!resistVertical && ydiff != 0) {
Chris@343 1826 if (dragMode == HorizontalDrag) dragMode = FreeDrag;
Chris@343 1827 else dragMode = VerticalDrag;
Chris@343 1828 }
Chris@343 1829 }
Chris@343 1830
Chris@343 1831 return dragMode;
Chris@343 1832 }
Chris@343 1833
Chris@174 1834 void
Chris@174 1835 Pane::dragExtendSelection(QMouseEvent *e)
Chris@174 1836 {
Chris@174 1837 int mouseFrame = getFrameForX(e->x());
Chris@174 1838 size_t resolution = 1;
Chris@174 1839 int snapFrameLeft = mouseFrame;
Chris@174 1840 int snapFrameRight = mouseFrame;
Chris@174 1841
Chris@174 1842 Layer *layer = getSelectedLayer();
Chris@174 1843 if (layer && !m_shiftPressed) {
Chris@174 1844 layer->snapToFeatureFrame(this, snapFrameLeft,
Chris@174 1845 resolution, Layer::SnapLeft);
Chris@174 1846 layer->snapToFeatureFrame(this, snapFrameRight,
Chris@174 1847 resolution, Layer::SnapRight);
Chris@174 1848 }
Chris@174 1849
Chris@174 1850 // std::cerr << "snap: frame = " << mouseFrame << ", start frame = " << m_selectionStartFrame << ", left = " << snapFrameLeft << ", right = " << snapFrameRight << std::endl;
Chris@174 1851
Chris@174 1852 if (snapFrameLeft < 0) snapFrameLeft = 0;
Chris@174 1853 if (snapFrameRight < 0) snapFrameRight = 0;
Chris@174 1854
Chris@174 1855 size_t min, max;
Chris@174 1856
Chris@248 1857 if (m_selectionStartFrame > size_t(snapFrameLeft)) {
Chris@174 1858 min = snapFrameLeft;
Chris@174 1859 max = m_selectionStartFrame;
Chris@248 1860 } else if (size_t(snapFrameRight) > m_selectionStartFrame) {
Chris@174 1861 min = m_selectionStartFrame;
Chris@174 1862 max = snapFrameRight;
Chris@174 1863 } else {
Chris@174 1864 min = snapFrameLeft;
Chris@174 1865 max = snapFrameRight;
Chris@174 1866 }
Chris@174 1867
Chris@174 1868 if (m_manager) {
Chris@333 1869 m_manager->setInProgressSelection(Selection(alignToReference(min),
Chris@333 1870 alignToReference(max)),
Chris@174 1871 !m_resizing && !m_ctrlPressed);
Chris@174 1872 }
Chris@174 1873
Chris@259 1874 edgeScrollMaybe(e->x());
Chris@259 1875
Chris@259 1876 update();
Chris@259 1877 }
Chris@259 1878
Chris@259 1879 void
Chris@259 1880 Pane::edgeScrollMaybe(int x)
Chris@259 1881 {
Chris@259 1882 int mouseFrame = getFrameForX(x);
Chris@259 1883
Chris@174 1884 bool doScroll = false;
Chris@174 1885 if (!m_manager) doScroll = true;
Chris@174 1886 if (!m_manager->isPlaying()) doScroll = true;
Chris@174 1887 if (m_followPlay != PlaybackScrollContinuous) doScroll = true;
Chris@174 1888
Chris@174 1889 if (doScroll) {
Chris@174 1890 int offset = mouseFrame - getStartFrame();
Chris@174 1891 int available = getEndFrame() - getStartFrame();
Chris@259 1892 int move = 0;
Chris@174 1893 if (offset >= available * 0.95) {
Chris@259 1894 move = int(offset - available * 0.95) + 1;
Chris@259 1895 } else if (offset <= available * 0.10) {
Chris@259 1896 move = int(available * 0.10 - offset) + 1;
Chris@259 1897 move = -move;
Chris@259 1898 }
Chris@259 1899 if (move != 0) {
Chris@174 1900 setCentreFrame(m_centreFrame + move);
Chris@259 1901 update();
Chris@174 1902 }
Chris@174 1903 }
Chris@174 1904 }
Chris@174 1905
Chris@174 1906 void
Chris@127 1907 Pane::mouseDoubleClickEvent(QMouseEvent *e)
Chris@127 1908 {
Chris@127 1909 if (e->buttons() & Qt::RightButton) {
Chris@127 1910 return;
Chris@127 1911 }
Chris@127 1912
Chris@343 1913 // std::cerr << "mouseDoubleClickEvent" << std::endl;
Chris@127 1914
Chris@127 1915 m_clickPos = e->pos();
Chris@127 1916 m_clickedInRange = true;
Chris@127 1917 m_shiftPressed = (e->modifiers() & Qt::ShiftModifier);
Chris@127 1918 m_ctrlPressed = (e->modifiers() & Qt::ControlModifier);
Chris@127 1919
Chris@127 1920 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@127 1921 if (m_manager) mode = m_manager->getToolMode();
Chris@127 1922
Chris@255 1923 bool relocate = (mode == ViewManager::NavigateMode ||
Chris@255 1924 (e->buttons() & Qt::MidButton));
Chris@255 1925
Chris@127 1926 if (mode == ViewManager::NavigateMode ||
Chris@127 1927 mode == ViewManager::EditMode) {
Chris@127 1928
Chris@127 1929 Layer *layer = getSelectedLayer();
Chris@127 1930 if (layer && layer->isLayerEditable()) {
Chris@255 1931 if (layer->editOpen(this, e)) relocate = false;
Chris@127 1932 }
Chris@280 1933
Chris@280 1934 } else if (mode == ViewManager::MeasureMode) {
Chris@280 1935
Chris@280 1936 Layer *layer = getTopLayer();
Chris@280 1937 if (layer) layer->measureDoubleClick(this, e);
Chris@280 1938 update();
Chris@127 1939 }
Chris@255 1940
Chris@255 1941 if (relocate) {
Chris@255 1942
Chris@255 1943 long f = getFrameForX(e->x());
Chris@255 1944
Chris@255 1945 setCentreFrame(f);
Chris@255 1946
Chris@255 1947 m_dragCentreFrame = f;
Chris@255 1948 m_dragStartMinValue = 0;
Chris@255 1949 m_dragMode = UnresolvedDrag;
Chris@255 1950
Chris@255 1951 float vmin, vmax, dmin, dmax;
Chris@255 1952 if (getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) {
Chris@255 1953 m_dragStartMinValue = dmin;
Chris@255 1954 }
Chris@255 1955 }
Chris@127 1956 }
Chris@127 1957
Chris@127 1958 void
Chris@290 1959 Pane::enterEvent(QEvent *)
Chris@290 1960 {
Chris@290 1961 m_mouseInWidget = true;
Chris@290 1962 }
Chris@290 1963
Chris@290 1964 void
Chris@127 1965 Pane::leaveEvent(QEvent *)
Chris@127 1966 {
Chris@290 1967 m_mouseInWidget = false;
Chris@127 1968 bool previouslyIdentifying = m_identifyFeatures;
Chris@127 1969 m_identifyFeatures = false;
Chris@127 1970 if (previouslyIdentifying) update();
Chris@189 1971 emit contextHelpChanged("");
Chris@127 1972 }
Chris@127 1973
Chris@127 1974 void
Chris@133 1975 Pane::resizeEvent(QResizeEvent *)
Chris@133 1976 {
Chris@133 1977 updateHeadsUpDisplay();
Chris@133 1978 }
Chris@133 1979
Chris@133 1980 void
Chris@127 1981 Pane::wheelEvent(QWheelEvent *e)
Chris@127 1982 {
Chris@127 1983 //std::cerr << "wheelEvent, delta " << e->delta() << std::endl;
Chris@127 1984
Chris@127 1985 int count = e->delta();
Chris@127 1986
Chris@127 1987 if (count > 0) {
Chris@127 1988 if (count >= 120) count /= 120;
Chris@127 1989 else count = 1;
Chris@127 1990 }
Chris@127 1991
Chris@127 1992 if (count < 0) {
Chris@127 1993 if (count <= -120) count /= 120;
Chris@127 1994 else count = -1;
Chris@127 1995 }
Chris@127 1996
Chris@127 1997 if (e->modifiers() & Qt::ControlModifier) {
Chris@127 1998
Chris@127 1999 // Scroll left or right, rapidly
Chris@127 2000
Chris@127 2001 if (getStartFrame() < 0 &&
Chris@127 2002 getEndFrame() >= getModelsEndFrame()) return;
Chris@127 2003
Chris@127 2004 long delta = ((width() / 2) * count * m_zoomLevel);
Chris@127 2005
Chris@127 2006 if (int(m_centreFrame) < delta) {
Chris@127 2007 setCentreFrame(0);
Chris@127 2008 } else if (int(m_centreFrame) - delta >= int(getModelsEndFrame())) {
Chris@127 2009 setCentreFrame(getModelsEndFrame());
Chris@127 2010 } else {
Chris@127 2011 setCentreFrame(m_centreFrame - delta);
Chris@127 2012 }
Chris@127 2013
Chris@256 2014 } else if (e->modifiers() & Qt::ShiftModifier) {
Chris@256 2015
Chris@256 2016 // Zoom vertically
Chris@256 2017
Chris@256 2018 if (m_vpan) {
Chris@256 2019 m_vpan->scroll(e->delta() > 0);
Chris@256 2020 }
Chris@256 2021
Chris@256 2022 } else if (e->modifiers() & Qt::AltModifier) {
Chris@256 2023
Chris@256 2024 // Zoom vertically
Chris@256 2025
Chris@256 2026 if (m_vthumb) {
Chris@256 2027 m_vthumb->scroll(e->delta() > 0);
Chris@256 2028 }
Chris@256 2029
Chris@127 2030 } else {
Chris@127 2031
Chris@127 2032 // Zoom in or out
Chris@127 2033
Chris@127 2034 int newZoomLevel = m_zoomLevel;
Chris@127 2035
Chris@127 2036 while (count > 0) {
Chris@127 2037 if (newZoomLevel <= 2) {
Chris@127 2038 newZoomLevel = 1;
Chris@127 2039 break;
Chris@127 2040 }
Chris@127 2041 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel - 1,
Chris@127 2042 ZoomConstraint::RoundDown);
Chris@127 2043 --count;
Chris@127 2044 }
Chris@127 2045
Chris@127 2046 while (count < 0) {
Chris@127 2047 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel + 1,
Chris@127 2048 ZoomConstraint::RoundUp);
Chris@127 2049 ++count;
Chris@127 2050 }
Chris@127 2051
Chris@127 2052 if (newZoomLevel != m_zoomLevel) {
Chris@127 2053 setZoomLevel(newZoomLevel);
Chris@127 2054 }
Chris@127 2055 }
Chris@127 2056
Chris@127 2057 emit paneInteractedWith();
Chris@127 2058 }
Chris@127 2059
Chris@132 2060 void
Chris@132 2061 Pane::horizontalThumbwheelMoved(int value)
Chris@132 2062 {
Chris@137 2063 //!!! dupe with updateHeadsUpDisplay
Chris@137 2064
Chris@132 2065 int count = 0;
Chris@132 2066 int level = 1;
Chris@137 2067
Chris@137 2068
Chris@137 2069 //!!! pull out into function (presumably in View)
Chris@137 2070 bool haveConstraint = false;
Chris@137 2071 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end();
Chris@137 2072 ++i) {
Chris@137 2073 if ((*i)->getZoomConstraint() && !(*i)->supportsOtherZoomLevels()) {
Chris@137 2074 haveConstraint = true;
Chris@137 2075 break;
Chris@137 2076 }
Chris@132 2077 }
Chris@132 2078
Chris@137 2079 if (haveConstraint) {
Chris@137 2080 while (true) {
Chris@137 2081 if (m_hthumb->getMaximumValue() - value == count) break;
Chris@137 2082 int newLevel = getZoomConstraintBlockSize(level + 1,
Chris@137 2083 ZoomConstraint::RoundUp);
Chris@137 2084 if (newLevel == level) break;
Chris@137 2085 level = newLevel;
Chris@137 2086 if (++count == 50) break;
Chris@137 2087 }
Chris@137 2088 } else {
Chris@137 2089 while (true) {
Chris@137 2090 if (m_hthumb->getMaximumValue() - value == count) break;
Chris@137 2091 int step = level / 10;
Chris@137 2092 int pwr = 0;
Chris@137 2093 while (step > 0) {
Chris@137 2094 ++pwr;
Chris@137 2095 step /= 2;
Chris@137 2096 }
Chris@137 2097 step = 1;
Chris@137 2098 while (pwr > 0) {
Chris@137 2099 step *= 2;
Chris@137 2100 --pwr;
Chris@137 2101 }
Chris@137 2102 // std::cerr << level << std::endl;
Chris@137 2103 level += step;
Chris@137 2104 if (++count == 100 || level > 262144) break;
Chris@137 2105 }
Chris@137 2106 }
Chris@137 2107
Chris@244 2108 // std::cerr << "new level is " << level << std::endl;
Chris@132 2109 setZoomLevel(level);
Chris@132 2110 }
Chris@132 2111
Chris@132 2112 void
Chris@132 2113 Pane::verticalThumbwheelMoved(int value)
Chris@132 2114 {
Chris@133 2115 Layer *layer = 0;
Chris@133 2116 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1);
Chris@133 2117 if (layer) {
Chris@133 2118 int defaultStep = 0;
Chris@133 2119 int max = layer->getVerticalZoomSteps(defaultStep);
Chris@133 2120 if (max == 0) {
Chris@133 2121 updateHeadsUpDisplay();
Chris@133 2122 return;
Chris@133 2123 }
Chris@133 2124 if (value > max) {
Chris@133 2125 value = max;
Chris@133 2126 }
Chris@133 2127 layer->setVerticalZoomStep(value);
Chris@174 2128 updateVerticalPanner();
Chris@133 2129 }
Chris@132 2130 }
Chris@132 2131
Chris@174 2132 void
Chris@174 2133 Pane::verticalPannerMoved(float x0, float y0, float w, float h)
Chris@174 2134 {
Chris@174 2135 float vmin, vmax, dmin, dmax;
Chris@174 2136 if (!getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) return;
Chris@174 2137 float y1 = y0 + h;
Chris@174 2138 float newmax = vmin + ((1.0 - y0) * (vmax - vmin));
Chris@174 2139 float newmin = vmin + ((1.0 - y1) * (vmax - vmin));
Chris@438 2140 // std::cerr << "verticalPannerMoved: (" << x0 << "," << y0 << "," << w
Chris@438 2141 // << "," << h << ") -> (" << newmin << "," << newmax << ")" << std::endl;
Chris@174 2142 setTopLayerDisplayExtents(newmin, newmax);
Chris@174 2143 }
Chris@174 2144
Chris@188 2145 void
Chris@188 2146 Pane::editVerticalPannerExtents()
Chris@188 2147 {
Chris@188 2148 if (!m_vpan || !m_manager || !m_manager->getZoomWheelsEnabled()) return;
Chris@188 2149
Chris@188 2150 float vmin, vmax, dmin, dmax;
Chris@188 2151 QString unit;
Chris@188 2152 if (!getTopLayerDisplayExtents(vmin, vmax, dmin, dmax, &unit)
Chris@188 2153 || vmax == vmin) {
Chris@188 2154 return;
Chris@188 2155 }
Chris@188 2156
Chris@188 2157 RangeInputDialog dialog(tr("Enter new range"),
Chris@188 2158 tr("New vertical display range, from %1 to %2 %4:")
Chris@188 2159 .arg(vmin).arg(vmax).arg(unit),
Chris@188 2160 unit, vmin, vmax, this);
Chris@188 2161 dialog.setRange(dmin, dmax);
Chris@188 2162
Chris@188 2163 if (dialog.exec() == QDialog::Accepted) {
Chris@188 2164 dialog.getRange(dmin, dmax);
Chris@188 2165 setTopLayerDisplayExtents(dmin, dmax);
Chris@188 2166 updateVerticalPanner();
Chris@188 2167 }
Chris@188 2168 }
Chris@188 2169
Chris@312 2170 void
Chris@437 2171 Pane::layerParametersChanged()
Chris@437 2172 {
Chris@437 2173 View::layerParametersChanged();
Chris@437 2174 updateHeadsUpDisplay();
Chris@437 2175 }
Chris@437 2176
Chris@437 2177 void
Chris@312 2178 Pane::dragEnterEvent(QDragEnterEvent *e)
Chris@312 2179 {
Chris@312 2180 QStringList formats(e->mimeData()->formats());
Chris@312 2181 std::cerr << "dragEnterEvent: format: "
Chris@312 2182 << formats.join(",").toStdString()
Chris@312 2183 << ", possibleActions: " << e->possibleActions()
Chris@312 2184 << ", proposedAction: " << e->proposedAction() << std::endl;
Chris@312 2185
Chris@312 2186 if (e->provides("text/uri-list") || e->provides("text/plain")) {
Chris@312 2187
Chris@312 2188 if (e->proposedAction() & Qt::CopyAction) {
Chris@312 2189 e->acceptProposedAction();
Chris@312 2190 } else {
Chris@312 2191 e->setDropAction(Qt::CopyAction);
Chris@312 2192 e->accept();
Chris@312 2193 }
Chris@312 2194 }
Chris@312 2195 }
Chris@312 2196
Chris@312 2197 void
Chris@312 2198 Pane::dropEvent(QDropEvent *e)
Chris@312 2199 {
Chris@312 2200 std::cerr << "dropEvent: text: \"" << e->mimeData()->text().toStdString()
Chris@312 2201 << "\"" << std::endl;
Chris@312 2202
Chris@312 2203 if (e->provides("text/uri-list") || e->provides("text/plain")) {
Chris@312 2204
Chris@312 2205 if (e->proposedAction() & Qt::CopyAction) {
Chris@312 2206 e->acceptProposedAction();
Chris@312 2207 } else {
Chris@312 2208 e->setDropAction(Qt::CopyAction);
Chris@312 2209 e->accept();
Chris@312 2210 }
Chris@312 2211
Chris@312 2212 if (e->provides("text/uri-list")) {
Chris@312 2213
Chris@312 2214 std::cerr << "accepting... data is \"" << e->encodedData("text/uri-list").data() << "\"" << std::endl;
Chris@312 2215 emit dropAccepted(QString::fromLocal8Bit
Chris@312 2216 (e->encodedData("text/uri-list").data())
Chris@312 2217 .split(QRegExp("[\\r\\n]+"),
Chris@312 2218 QString::SkipEmptyParts));
Chris@312 2219 } else {
Chris@312 2220 emit dropAccepted(QString::fromLocal8Bit
Chris@312 2221 (e->encodedData("text/plain").data()));
Chris@312 2222 }
Chris@312 2223 }
Chris@312 2224 }
Chris@312 2225
Chris@127 2226 bool
Chris@127 2227 Pane::editSelectionStart(QMouseEvent *e)
Chris@127 2228 {
Chris@127 2229 if (!m_identifyFeatures ||
Chris@127 2230 !m_manager ||
Chris@127 2231 m_manager->getToolMode() != ViewManager::EditMode) {
Chris@127 2232 return false;
Chris@127 2233 }
Chris@127 2234
Chris@127 2235 bool closeToLeft, closeToRight;
Chris@127 2236 Selection s(getSelectionAt(e->x(), closeToLeft, closeToRight));
Chris@127 2237 if (s.isEmpty()) return false;
Chris@127 2238 m_editingSelection = s;
Chris@127 2239 m_editingSelectionEdge = (closeToLeft ? -1 : closeToRight ? 1 : 0);
Chris@127 2240 m_mousePos = e->pos();
Chris@127 2241 return true;
Chris@127 2242 }
Chris@127 2243
Chris@127 2244 bool
Chris@127 2245 Pane::editSelectionDrag(QMouseEvent *e)
Chris@127 2246 {
Chris@127 2247 if (m_editingSelection.isEmpty()) return false;
Chris@127 2248 m_mousePos = e->pos();
Chris@127 2249 update();
Chris@127 2250 return true;
Chris@127 2251 }
Chris@127 2252
Chris@127 2253 bool
Chris@248 2254 Pane::editSelectionEnd(QMouseEvent *)
Chris@127 2255 {
Chris@127 2256 if (m_editingSelection.isEmpty()) return false;
Chris@127 2257
Chris@127 2258 int offset = m_mousePos.x() - m_clickPos.x();
Chris@127 2259 Layer *layer = getSelectedLayer();
Chris@127 2260
Chris@127 2261 if (offset == 0 || !layer) {
Chris@127 2262 m_editingSelection = Selection();
Chris@127 2263 return true;
Chris@127 2264 }
Chris@127 2265
Chris@127 2266 int p0 = getXForFrame(m_editingSelection.getStartFrame()) + offset;
Chris@127 2267 int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset;
Chris@127 2268
Chris@127 2269 long f0 = getFrameForX(p0);
Chris@127 2270 long f1 = getFrameForX(p1);
Chris@127 2271
Chris@127 2272 Selection newSelection(f0, f1);
Chris@127 2273
Chris@127 2274 if (m_editingSelectionEdge == 0) {
Chris@127 2275
Chris@127 2276 CommandHistory::getInstance()->startCompoundOperation
Chris@127 2277 (tr("Drag Selection"), true);
Chris@127 2278
Chris@127 2279 layer->moveSelection(m_editingSelection, f0);
Chris@127 2280
Chris@127 2281 } else {
Chris@127 2282
Chris@127 2283 CommandHistory::getInstance()->startCompoundOperation
Chris@127 2284 (tr("Resize Selection"), true);
Chris@127 2285
Chris@127 2286 if (m_editingSelectionEdge < 0) {
Chris@127 2287 f1 = m_editingSelection.getEndFrame();
Chris@127 2288 } else {
Chris@127 2289 f0 = m_editingSelection.getStartFrame();
Chris@127 2290 }
Chris@127 2291
Chris@127 2292 newSelection = Selection(f0, f1);
Chris@127 2293 layer->resizeSelection(m_editingSelection, newSelection);
Chris@127 2294 }
Chris@127 2295
Chris@127 2296 m_manager->removeSelection(m_editingSelection);
Chris@127 2297 m_manager->addSelection(newSelection);
Chris@127 2298
Chris@127 2299 CommandHistory::getInstance()->endCompoundOperation();
Chris@127 2300
Chris@127 2301 m_editingSelection = Selection();
Chris@127 2302 return true;
Chris@127 2303 }
Chris@127 2304
Chris@127 2305 void
Chris@127 2306 Pane::toolModeChanged()
Chris@127 2307 {
Chris@127 2308 ViewManager::ToolMode mode = m_manager->getToolMode();
Chris@127 2309 // std::cerr << "Pane::toolModeChanged(" << mode << ")" << std::endl;
Chris@127 2310
Chris@267 2311 if (mode == ViewManager::MeasureMode && !m_measureCursor1) {
Chris@267 2312 m_measureCursor1 = new QCursor(QBitmap(":/icons/measure1cursor.xbm"),
Chris@267 2313 QBitmap(":/icons/measure1mask.xbm"),
Chris@267 2314 15, 14);
Chris@267 2315 m_measureCursor2 = new QCursor(QBitmap(":/icons/measure2cursor.xbm"),
Chris@267 2316 QBitmap(":/icons/measure2mask.xbm"),
Chris@267 2317 16, 17);
Chris@257 2318 }
Chris@257 2319
Chris@127 2320 switch (mode) {
Chris@127 2321
Chris@127 2322 case ViewManager::NavigateMode:
Chris@127 2323 setCursor(Qt::PointingHandCursor);
Chris@127 2324 break;
Chris@127 2325
Chris@127 2326 case ViewManager::SelectMode:
Chris@127 2327 setCursor(Qt::ArrowCursor);
Chris@127 2328 break;
Chris@127 2329
Chris@127 2330 case ViewManager::EditMode:
Chris@127 2331 setCursor(Qt::UpArrowCursor);
Chris@127 2332 break;
Chris@127 2333
Chris@127 2334 case ViewManager::DrawMode:
Chris@127 2335 setCursor(Qt::CrossCursor);
Chris@127 2336 break;
Chris@335 2337
Chris@335 2338 case ViewManager::EraseMode:
Chris@335 2339 setCursor(Qt::CrossCursor);
Chris@335 2340 break;
Chris@257 2341
Chris@257 2342 case ViewManager::MeasureMode:
Chris@267 2343 if (m_measureCursor1) setCursor(*m_measureCursor1);
Chris@257 2344 break;
Chris@257 2345
Chris@127 2346 /*
Chris@127 2347 case ViewManager::TextMode:
Chris@127 2348 setCursor(Qt::IBeamCursor);
Chris@127 2349 break;
Chris@127 2350 */
Chris@127 2351 }
Chris@127 2352 }
Chris@127 2353
Chris@133 2354 void
Chris@133 2355 Pane::zoomWheelsEnabledChanged()
Chris@133 2356 {
Chris@133 2357 updateHeadsUpDisplay();
Chris@133 2358 update();
Chris@133 2359 }
Chris@133 2360
Chris@133 2361 void
Chris@224 2362 Pane::viewZoomLevelChanged(View *v, unsigned long z, bool locked)
Chris@133 2363 {
Chris@212 2364 // std::cerr << "Pane[" << this << "]::zoomLevelChanged (global now "
Chris@212 2365 // << (m_manager ? m_manager->getGlobalZoom() : 0) << ")" << std::endl;
Chris@192 2366
Chris@224 2367 View::viewZoomLevelChanged(v, z, locked);
Chris@224 2368
Chris@232 2369 if (m_hthumb && !m_hthumb->isVisible()) return;
Chris@224 2370
Chris@222 2371 if (v != this) {
Chris@222 2372 if (!locked || !m_followZoom) return;
Chris@222 2373 }
Chris@222 2374
Chris@133 2375 if (m_manager && m_manager->getZoomWheelsEnabled()) {
Chris@133 2376 updateHeadsUpDisplay();
Chris@133 2377 }
Chris@133 2378 }
Chris@133 2379
Chris@133 2380 void
Chris@133 2381 Pane::propertyContainerSelected(View *v, PropertyContainer *pc)
Chris@133 2382 {
Chris@133 2383 Layer *layer = 0;
Chris@133 2384
Chris@133 2385 if (getLayerCount() > 0) {
Chris@133 2386 layer = getLayer(getLayerCount() - 1);
Chris@133 2387 disconnect(layer, SIGNAL(verticalZoomChanged()),
Chris@133 2388 this, SLOT(verticalZoomChanged()));
Chris@133 2389 }
Chris@133 2390
Chris@133 2391 View::propertyContainerSelected(v, pc);
Chris@133 2392 updateHeadsUpDisplay();
Chris@133 2393
Chris@187 2394 if (m_vthumb) {
Chris@187 2395 RangeMapper *rm = 0;
Chris@187 2396 if (layer) rm = layer->getNewVerticalZoomRangeMapper();
Chris@187 2397 if (rm) m_vthumb->setRangeMapper(rm);
Chris@187 2398 }
Chris@187 2399
Chris@133 2400 if (getLayerCount() > 0) {
Chris@133 2401 layer = getLayer(getLayerCount() - 1);
Chris@133 2402 connect(layer, SIGNAL(verticalZoomChanged()),
Chris@133 2403 this, SLOT(verticalZoomChanged()));
Chris@133 2404 }
Chris@133 2405 }
Chris@133 2406
Chris@133 2407 void
Chris@133 2408 Pane::verticalZoomChanged()
Chris@133 2409 {
Chris@133 2410 Layer *layer = 0;
Chris@133 2411
Chris@133 2412 if (getLayerCount() > 0) {
Chris@133 2413
Chris@133 2414 layer = getLayer(getLayerCount() - 1);
Chris@133 2415
Chris@133 2416 if (m_vthumb && m_vthumb->isVisible()) {
Chris@133 2417 m_vthumb->setValue(layer->getCurrentVerticalZoomStep());
Chris@133 2418 }
Chris@133 2419 }
Chris@133 2420 }
Chris@133 2421
Chris@189 2422 void
Chris@189 2423 Pane::updateContextHelp(const QPoint *pos)
Chris@189 2424 {
Chris@189 2425 QString help = "";
Chris@189 2426
Chris@189 2427 if (m_clickedInRange) {
Chris@189 2428 emit contextHelpChanged("");
Chris@189 2429 return;
Chris@189 2430 }
Chris@189 2431
Chris@189 2432 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@189 2433 if (m_manager) mode = m_manager->getToolMode();
Chris@189 2434
Chris@189 2435 bool editable = false;
Chris@189 2436 Layer *layer = getSelectedLayer();
Chris@189 2437 if (layer && layer->isLayerEditable()) {
Chris@189 2438 editable = true;
Chris@189 2439 }
Chris@189 2440
Chris@189 2441 if (mode == ViewManager::NavigateMode) {
Chris@189 2442
Chris@189 2443 help = tr("Click and drag to navigate");
Chris@189 2444
Chris@189 2445 } else if (mode == ViewManager::SelectMode) {
Chris@189 2446
Chris@217 2447 if (!hasTopLayerTimeXAxis()) return;
Chris@217 2448
Chris@189 2449 bool haveSelection = (m_manager && !m_manager->getSelections().empty());
Chris@189 2450
Chris@189 2451 if (haveSelection) {
Chris@189 2452 if (editable) {
Chris@189 2453 help = tr("Click and drag to select a range; hold Shift to avoid snapping to items; hold Ctrl for multi-select; middle-click and drag to navigate");
Chris@189 2454 } else {
Chris@189 2455 help = tr("Click and drag to select a range; hold Ctrl for multi-select; middle-click and drag to navigate");
Chris@189 2456 }
Chris@189 2457
Chris@189 2458 if (pos) {
Chris@189 2459 bool closeToLeft = false, closeToRight = false;
Chris@189 2460 Selection selection = getSelectionAt(pos->x(), closeToLeft, closeToRight);
Chris@189 2461 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) {
Chris@189 2462
Chris@189 2463 help = tr("Click and drag to move the selection boundary");
Chris@189 2464 }
Chris@189 2465 }
Chris@189 2466 } else {
Chris@189 2467 if (editable) {
Chris@189 2468 help = tr("Click and drag to select a range; hold Shift to avoid snapping to items; middle-click to navigate");
Chris@189 2469 } else {
Chris@189 2470 help = tr("Click and drag to select a range; middle-click and drag to navigate");
Chris@189 2471 }
Chris@189 2472 }
Chris@189 2473
Chris@189 2474 } else if (mode == ViewManager::DrawMode) {
Chris@189 2475
Chris@189 2476 //!!! could call through to a layer function to find out exact meaning
Chris@189 2477 if (editable) {
Chris@189 2478 help = tr("Click to add a new item in the active layer");
Chris@189 2479 }
Chris@335 2480
Chris@335 2481 } else if (mode == ViewManager::EraseMode) {
Chris@335 2482
Chris@335 2483 //!!! could call through to a layer function to find out exact meaning
Chris@335 2484 if (editable) {
Chris@335 2485 help = tr("Click to erase an item from the active layer");
Chris@335 2486 }
Chris@189 2487
Chris@189 2488 } else if (mode == ViewManager::EditMode) {
Chris@189 2489
Chris@189 2490 //!!! could call through to layer
Chris@189 2491 if (editable) {
Chris@189 2492 help = tr("Click and drag an item in the active layer to move it");
Chris@189 2493 if (pos) {
Chris@189 2494 bool closeToLeft = false, closeToRight = false;
Chris@189 2495 Selection selection = getSelectionAt(pos->x(), closeToLeft, closeToRight);
Chris@189 2496 if (!selection.isEmpty()) {
Chris@189 2497 help = tr("Click and drag to move all items in the selected range");
Chris@189 2498 }
Chris@189 2499 }
Chris@189 2500 }
Chris@189 2501 }
Chris@189 2502
Chris@189 2503 emit contextHelpChanged(help);
Chris@189 2504 }
Chris@189 2505
Chris@189 2506 void
Chris@189 2507 Pane::mouseEnteredWidget()
Chris@189 2508 {
Chris@189 2509 QWidget *w = dynamic_cast<QWidget *>(sender());
Chris@189 2510 if (!w) return;
Chris@189 2511
Chris@189 2512 if (w == m_vpan) {
Chris@189 2513 emit contextHelpChanged(tr("Click and drag to adjust the visible range of the vertical scale"));
Chris@189 2514 } else if (w == m_vthumb) {
Chris@189 2515 emit contextHelpChanged(tr("Click and drag to adjust the vertical zoom level"));
Chris@189 2516 } else if (w == m_hthumb) {
Chris@189 2517 emit contextHelpChanged(tr("Click and drag to adjust the horizontal zoom level"));
Chris@189 2518 } else if (w == m_reset) {
Chris@189 2519 emit contextHelpChanged(tr("Reset horizontal and vertical zoom levels to their defaults"));
Chris@189 2520 }
Chris@189 2521 }
Chris@189 2522
Chris@189 2523 void
Chris@189 2524 Pane::mouseLeftWidget()
Chris@189 2525 {
Chris@189 2526 emit contextHelpChanged("");
Chris@189 2527 }
Chris@189 2528
Chris@316 2529 void
Chris@316 2530 Pane::toXml(QTextStream &stream,
Chris@316 2531 QString indent, QString extraAttributes) const
Chris@127 2532 {
Chris@316 2533 View::toXml
Chris@316 2534 (stream, indent,
Chris@127 2535 QString("type=\"pane\" centreLineVisible=\"%1\" height=\"%2\" %3")
Chris@127 2536 .arg(m_centreLineVisible).arg(height()).arg(extraAttributes));
Chris@127 2537 }
Chris@127 2538
Chris@127 2539