annotate view/Pane.cpp @ 1605:ae2d5f8ff005

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