annotate view/Pane.cpp @ 1548:bd6af89982d7

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