annotate view/Pane.cpp @ 1212:a1ee3108d1d3 3.0-integration

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