annotate view/Pane.cpp @ 1447:8afea53332f3 single-point

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