annotate view/Pane.cpp @ 1127:9fb8dfd7ce4c spectrogram-minor-refactor

Fix threshold in spectrogram -- it wasn't working in the last release. There is a new protocol for this. Formerly the threshold parameter had a range from -50dB to 0 with the default at -50, and -50 treated internally as "no threshold". However, there was a hardcoded, hidden internal threshold for spectrogram colour mapping at -80dB with anything below this being rounded to zero. Now the threshold parameter has range -81 to -1 with the default at -80, -81 is treated internally as "no threshold", and there is no hidden internal threshold. So the default behaviour is the same as before, an effective -80dB threshold, but it is now possible to change this in both directions. Sessions reloaded from prior versions may look slightly different because, if the session says there should be no threshold, there will now actually be no threshold instead of having the hidden internal one. Still need to do something in the UI to make it apparent that the -81dB setting removes the threshold entirely. This is at least no worse than the previous, also obscured, magic -50dB setting.
author Chris Cannam
date Mon, 01 Aug 2016 16:21:01 +0100
parents ee01a4062747
children ba379b4d4555
rev   line source
Chris@127 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@127 2
Chris@127 3 /*
Chris@127 4 Sonic Visualiser
Chris@127 5 An audio file viewer and annotation editor.
Chris@127 6 Centre for Digital Music, Queen Mary, University of London.
Chris@264 7 This file copyright 2006-2007 Chris Cannam and QMUL.
Chris@127 8
Chris@127 9 This program is free software; you can redistribute it and/or
Chris@127 10 modify it under the terms of the GNU General Public License as
Chris@127 11 published by the Free Software Foundation; either version 2 of the
Chris@127 12 License, or (at your option) any later version. See the file
Chris@127 13 COPYING included with this distribution for more information.
Chris@127 14 */
Chris@127 15
Chris@128 16 #include "Pane.h"
Chris@128 17 #include "layer/Layer.h"
Chris@128 18 #include "data/model/Model.h"
Chris@127 19 #include "base/ZoomConstraint.h"
Chris@127 20 #include "base/RealTime.h"
Chris@127 21 #include "base/Profiler.h"
Chris@128 22 #include "ViewManager.h"
Chris@376 23 #include "widgets/CommandHistory.h"
Chris@376 24 #include "widgets/TextAbbrev.h"
Chris@338 25 #include "base/Preferences.h"
Chris@127 26 #include "layer/WaveformLayer.h"
Chris@928 27 #include "layer/TimeRulerLayer.h"
Chris@1078 28 #include "layer/PaintAssistant.h"
Chris@127 29
gyorgyf@646 30 // GF: added so we can propagate the mouse move event to the note layer for context handling.
gyorgyf@646 31 #include "layer/LayerFactory.h"
gyorgyf@646 32 #include "layer/FlexiNoteLayer.h"
gyorgyf@646 33
gyorgyf@646 34
Chris@326 35 //!!! ugh
Chris@326 36 #include "data/model/WaveFileModel.h"
Chris@326 37
Chris@127 38 #include <QPaintEvent>
Chris@127 39 #include <QPainter>
Chris@257 40 #include <QBitmap>
Chris@312 41 #include <QDragEnterEvent>
Chris@312 42 #include <QDropEvent>
Chris@257 43 #include <QCursor>
Chris@316 44 #include <QTextStream>
Chris@616 45 #include <QMimeData>
Chris@802 46 #include <QApplication>
Chris@316 47
Chris@127 48 #include <iostream>
Chris@127 49 #include <cmath>
Chris@127 50
Chris@133 51 //!!! for HUD -- pull out into a separate class
Chris@133 52 #include <QFrame>
Chris@133 53 #include <QGridLayout>
Chris@133 54 #include <QPushButton>
Chris@133 55 #include "widgets/Thumbwheel.h"
Chris@172 56 #include "widgets/Panner.h"
Chris@188 57 #include "widgets/RangeInputDialog.h"
Chris@189 58 #include "widgets/NotifyingPushButton.h"
Chris@133 59
Chris@282 60 #include "widgets/KeyReference.h" //!!! should probably split KeyReference into a data class in base and another that shows the widget
Chris@282 61
Chris@363 62 //#define DEBUG_PANE
Chris@363 63
Chris@682 64
Chris@682 65
Chris@127 66
Chris@267 67 QCursor *Pane::m_measureCursor1 = 0;
Chris@267 68 QCursor *Pane::m_measureCursor2 = 0;
Chris@262 69
Chris@127 70 Pane::Pane(QWidget *w) :
Chris@127 71 View(w, true),
Chris@127 72 m_identifyFeatures(false),
Chris@127 73 m_clickedInRange(false),
Chris@127 74 m_shiftPressed(false),
Chris@127 75 m_ctrlPressed(false),
Chris@510 76 m_altPressed(false),
Chris@127 77 m_navigating(false),
Chris@127 78 m_resizing(false),
Chris@343 79 m_editing(false),
Chris@343 80 m_releasing(false),
Chris@133 81 m_centreLineVisible(true),
Chris@222 82 m_scaleWidth(0),
Chris@826 83 m_pendingWheelAngle(0),
Chris@237 84 m_headsUpDisplay(0),
Chris@237 85 m_vpan(0),
Chris@237 86 m_hthumb(0),
Chris@237 87 m_vthumb(0),
Chris@290 88 m_reset(0),
Chris@802 89 m_mouseInWidget(false),
Chris@802 90 m_playbackFrameMoveScheduled(false),
Chris@802 91 m_playbackFrameMoveTo(0)
Chris@127 92 {
Chris@127 93 setObjectName("Pane");
Chris@127 94 setMouseTracking(true);
Chris@312 95 setAcceptDrops(true);
Chris@133 96
Chris@133 97 updateHeadsUpDisplay();
Chris@456 98
Chris@730 99 connect(this, SIGNAL(regionOutlined(QRect)),
Chris@730 100 this, SLOT(zoomToRegion(QRect)));
Chris@730 101
Chris@728 102 cerr << "Pane::Pane(" << this << ") returning" << endl;
Chris@133 103 }
Chris@133 104
Chris@133 105 void
Chris@133 106 Pane::updateHeadsUpDisplay()
Chris@133 107 {
Chris@382 108 Profiler profiler("Pane::updateHeadsUpDisplay");
Chris@187 109
Chris@192 110 if (!isVisible()) return;
Chris@192 111
Chris@132 112 /*
Chris@132 113 int count = 0;
Chris@132 114 int currentLevel = 1;
Chris@132 115 int level = 1;
Chris@132 116 while (true) {
Chris@132 117 if (getZoomLevel() == level) currentLevel = count;
Chris@132 118 int newLevel = getZoomConstraintBlockSize(level + 1,
Chris@132 119 ZoomConstraint::RoundUp);
Chris@132 120 if (newLevel == level) break;
Chris@132 121 if (newLevel == 131072) break; //!!! just because
Chris@132 122 level = newLevel;
Chris@132 123 ++count;
Chris@132 124 }
Chris@132 125
Chris@682 126 cerr << "Have " << count+1 << " zoom levels" << endl;
Chris@132 127 */
Chris@133 128
Chris@188 129 Layer *layer = 0;
Chris@188 130 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1);
Chris@188 131
Chris@133 132 if (!m_headsUpDisplay) {
Chris@133 133
Chris@133 134 m_headsUpDisplay = new QFrame(this);
Chris@133 135
Chris@133 136 QGridLayout *layout = new QGridLayout;
Chris@133 137 layout->setMargin(0);
Chris@133 138 layout->setSpacing(0);
Chris@133 139 m_headsUpDisplay->setLayout(layout);
Chris@133 140
Chris@133 141 m_hthumb = new Thumbwheel(Qt::Horizontal);
Chris@187 142 m_hthumb->setObjectName(tr("Horizontal Zoom"));
Chris@260 143 m_hthumb->setCursor(Qt::ArrowCursor);
Chris@173 144 layout->addWidget(m_hthumb, 1, 0, 1, 2);
Chris@133 145 m_hthumb->setFixedWidth(70);
Chris@133 146 m_hthumb->setFixedHeight(16);
Chris@133 147 m_hthumb->setDefaultValue(0);
Chris@908 148 m_hthumb->setSpeed(0.6f);
Chris@133 149 connect(m_hthumb, SIGNAL(valueChanged(int)), this,
Chris@133 150 SLOT(horizontalThumbwheelMoved(int)));
Chris@189 151 connect(m_hthumb, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@189 152 connect(m_hthumb, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@172 153
Chris@172 154 m_vpan = new Panner;
Chris@260 155 m_vpan->setCursor(Qt::ArrowCursor);
Chris@172 156 layout->addWidget(m_vpan, 0, 1);
Chris@173 157 m_vpan->setFixedWidth(12);
Chris@172 158 m_vpan->setFixedHeight(70);
Chris@174 159 m_vpan->setAlpha(80, 130);
Chris@174 160 connect(m_vpan, SIGNAL(rectExtentsChanged(float, float, float, float)),
Chris@174 161 this, SLOT(verticalPannerMoved(float, float, float, float)));
Chris@188 162 connect(m_vpan, SIGNAL(doubleClicked()),
Chris@188 163 this, SLOT(editVerticalPannerExtents()));
Chris@189 164 connect(m_vpan, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@189 165 connect(m_vpan, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@172 166
Chris@133 167 m_vthumb = new Thumbwheel(Qt::Vertical);
Chris@187 168 m_vthumb->setObjectName(tr("Vertical Zoom"));
Chris@260 169 m_vthumb->setCursor(Qt::ArrowCursor);
Chris@172 170 layout->addWidget(m_vthumb, 0, 2);
Chris@133 171 m_vthumb->setFixedWidth(16);
Chris@133 172 m_vthumb->setFixedHeight(70);
Chris@133 173 connect(m_vthumb, SIGNAL(valueChanged(int)), this,
Chris@133 174 SLOT(verticalThumbwheelMoved(int)));
Chris@189 175 connect(m_vthumb, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@189 176 connect(m_vthumb, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@133 177
Chris@188 178 if (layer) {
Chris@188 179 RangeMapper *rm = layer->getNewVerticalZoomRangeMapper();
Chris@188 180 if (rm) m_vthumb->setRangeMapper(rm);
Chris@188 181 }
Chris@188 182
Chris@189 183 m_reset = new NotifyingPushButton;
Chris@713 184 m_reset->setFlat(true);
Chris@260 185 m_reset->setCursor(Qt::ArrowCursor);
Chris@189 186 m_reset->setFixedHeight(16);
Chris@189 187 m_reset->setFixedWidth(16);
Chris@499 188 m_reset->setIcon(QPixmap(":/icons/zoom-reset.png"));
Chris@501 189 m_reset->setToolTip(tr("Reset zoom to default"));
Chris@189 190 layout->addWidget(m_reset, 1, 2);
Chris@492 191
Chris@492 192 layout->setColumnStretch(0, 20);
Chris@492 193
Chris@189 194 connect(m_reset, SIGNAL(clicked()), m_hthumb, SLOT(resetToDefault()));
Chris@189 195 connect(m_reset, SIGNAL(clicked()), m_vthumb, SLOT(resetToDefault()));
Chris@189 196 connect(m_reset, SIGNAL(clicked()), m_vpan, SLOT(resetToDefault()));
Chris@189 197 connect(m_reset, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@189 198 connect(m_reset, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@133 199 }
Chris@133 200
Chris@133 201 int count = 0;
Chris@133 202 int current = 0;
Chris@133 203 int level = 1;
Chris@133 204
Chris@137 205 //!!! pull out into function (presumably in View)
Chris@137 206 bool haveConstraint = false;
Chris@835 207 for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end();
Chris@137 208 ++i) {
Chris@137 209 if ((*i)->getZoomConstraint() && !(*i)->supportsOtherZoomLevels()) {
Chris@137 210 haveConstraint = true;
Chris@137 211 break;
Chris@137 212 }
Chris@137 213 }
Chris@137 214
Chris@137 215 if (haveConstraint) {
Chris@137 216 while (true) {
Chris@137 217 if (getZoomLevel() == level) current = count;
Chris@137 218 int newLevel = getZoomConstraintBlockSize(level + 1,
Chris@137 219 ZoomConstraint::RoundUp);
Chris@137 220 if (newLevel == level) break;
Chris@137 221 level = newLevel;
Chris@137 222 if (++count == 50) break;
Chris@137 223 }
Chris@137 224 } else {
Chris@137 225 // if we have no particular constraints, we can really spread out
Chris@137 226 while (true) {
Chris@137 227 if (getZoomLevel() >= level) current = count;
Chris@137 228 int step = level / 10;
Chris@137 229 int pwr = 0;
Chris@137 230 while (step > 0) {
Chris@137 231 ++pwr;
Chris@137 232 step /= 2;
Chris@137 233 }
Chris@137 234 step = 1;
Chris@137 235 while (pwr > 0) {
Chris@137 236 step *= 2;
Chris@137 237 --pwr;
Chris@137 238 }
Chris@682 239 // cerr << level << endl;
Chris@137 240 level += step;
Chris@137 241 if (++count == 100 || level > 262144) break;
Chris@137 242 }
Chris@133 243 }
Chris@133 244
Chris@682 245 // cerr << "Have " << count << " zoom levels" << endl;
Chris@133 246
Chris@133 247 m_hthumb->setMinimumValue(0);
Chris@133 248 m_hthumb->setMaximumValue(count);
Chris@133 249 m_hthumb->setValue(count - current);
Chris@133 250
Chris@682 251 // cerr << "set value to " << count-current << endl;
Chris@682 252
Chris@682 253 // cerr << "default value is " << m_hthumb->getDefaultValue() << endl;
Chris@133 254
Chris@133 255 if (count != 50 && m_hthumb->getDefaultValue() == 0) {
Chris@133 256 m_hthumb->setDefaultValue(count - current);
Chris@682 257 // cerr << "set default value to " << m_hthumb->getDefaultValue() << endl;
Chris@133 258 }
Chris@133 259
Chris@204 260 bool haveVThumb = false;
Chris@204 261
Chris@133 262 if (layer) {
Chris@133 263 int defaultStep = 0;
Chris@133 264 int max = layer->getVerticalZoomSteps(defaultStep);
Chris@133 265 if (max == 0) {
Chris@133 266 m_vthumb->hide();
Chris@133 267 } else {
Chris@204 268 haveVThumb = true;
Chris@133 269 m_vthumb->show();
Chris@187 270 m_vthumb->blockSignals(true);
Chris@133 271 m_vthumb->setMinimumValue(0);
Chris@133 272 m_vthumb->setMaximumValue(max);
Chris@133 273 m_vthumb->setDefaultValue(defaultStep);
Chris@133 274 m_vthumb->setValue(layer->getCurrentVerticalZoomStep());
Chris@187 275 m_vthumb->blockSignals(false);
Chris@135 276
Chris@682 277 // cerr << "Vertical thumbwheel: min 0, max " << max
Chris@205 278 // << ", default " << defaultStep << ", value "
Chris@682 279 // << m_vthumb->getValue() << endl;
Chris@135 280
Chris@133 281 }
Chris@133 282 }
Chris@133 283
Chris@174 284 updateVerticalPanner();
Chris@174 285
Chris@133 286 if (m_manager && m_manager->getZoomWheelsEnabled() &&
Chris@133 287 width() > 120 && height() > 100) {
Chris@165 288 if (!m_headsUpDisplay->isVisible()) {
Chris@165 289 m_headsUpDisplay->show();
Chris@165 290 }
Chris@204 291 if (haveVThumb) {
Chris@204 292 m_headsUpDisplay->setFixedHeight(m_vthumb->height() + m_hthumb->height());
Chris@133 293 m_headsUpDisplay->move(width() - 86, height() - 86);
Chris@133 294 } else {
Chris@204 295 m_headsUpDisplay->setFixedHeight(m_hthumb->height());
Chris@204 296 m_headsUpDisplay->move(width() - 86, height() - 16);
Chris@133 297 }
Chris@133 298 } else {
Chris@133 299 m_headsUpDisplay->hide();
Chris@133 300 }
Chris@127 301 }
Chris@127 302
Chris@174 303 void
Chris@174 304 Pane::updateVerticalPanner()
Chris@174 305 {
Chris@174 306 if (!m_vpan || !m_manager || !m_manager->getZoomWheelsEnabled()) return;
Chris@174 307
Chris@208 308 // In principle we should show or hide the panner on the basis of
Chris@208 309 // whether the top layer has adjustable display extents, and we do
Chris@208 310 // that below. However, we have no basis for layout of the panner
Chris@208 311 // if the vertical scroll wheel is not also present. So if we
Chris@208 312 // have no vertical scroll wheel, we should remove the panner as
Chris@208 313 // well. Ideally any layer that implements display extents should
Chris@208 314 // implement vertical zoom steps as well, but they don't all at
Chris@208 315 // the moment.
Chris@208 316
Chris@208 317 Layer *layer = 0;
Chris@208 318 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1);
Chris@208 319 int discard;
Chris@208 320 if (layer && layer->getVerticalZoomSteps(discard) == 0) {
Chris@208 321 m_vpan->hide();
Chris@208 322 return;
Chris@208 323 }
Chris@208 324
Chris@908 325 double vmin, vmax, dmin, dmax;
Chris@174 326 if (getTopLayerDisplayExtents(vmin, vmax, dmin, dmax) && vmax != vmin) {
Chris@908 327 double y0 = (dmin - vmin) / (vmax - vmin);
Chris@908 328 double y1 = (dmax - vmin) / (vmax - vmin);
Chris@174 329 m_vpan->blockSignals(true);
Chris@908 330 m_vpan->setRectExtents(0, float(1.0 - y1), 1, float(y1 - y0));
Chris@174 331 m_vpan->blockSignals(false);
Chris@174 332 m_vpan->show();
Chris@174 333 } else {
Chris@174 334 m_vpan->hide();
Chris@174 335 }
Chris@174 336 }
Chris@174 337
Chris@127 338 bool
Chris@127 339 Pane::shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos) const
Chris@127 340 {
Chris@127 341 QPoint discard;
Chris@127 342 bool b0, b1;
Chris@127 343
Chris@711 344 if (m_manager && m_manager->getToolModeFor(this) == ViewManager::MeasureMode) {
Chris@262 345 return false;
Chris@262 346 }
matthiasm@651 347
Chris@326 348 if (m_manager && !m_manager->shouldIlluminateLocalFeatures()) {
Chris@326 349 return false;
Chris@326 350 }
Chris@326 351
Chris@840 352 if (layer == getInteractionLayer() &&
Chris@753 353 !shouldIlluminateLocalSelection(discard, b0, b1)) {
Chris@753 354
Chris@753 355 pos = m_identifyPoint;
Chris@753 356 return m_identifyFeatures;
Chris@127 357 }
Chris@127 358
Chris@127 359 return false;
Chris@127 360 }
Chris@127 361
Chris@127 362 bool
Chris@127 363 Pane::shouldIlluminateLocalSelection(QPoint &pos,
gyorgyf@645 364 bool &closeToLeft,
gyorgyf@645 365 bool &closeToRight) const
Chris@127 366 {
Chris@127 367 if (m_identifyFeatures &&
Chris@731 368 m_manager &&
Chris@731 369 m_manager->getToolModeFor(this) == ViewManager::EditMode &&
Chris@731 370 !m_manager->getSelections().empty() &&
Chris@731 371 !selectionIsBeingEdited()) {
gyorgyf@645 372
Chris@753 373 Selection s(getSelectionAt(m_identifyPoint.x(),
Chris@753 374 closeToLeft, closeToRight));
Chris@753 375
Chris@753 376 if (!s.isEmpty()) {
Chris@840 377 if (getInteractionLayer() && getInteractionLayer()->isLayerEditable()) {
Chris@753 378
Chris@753 379 pos = m_identifyPoint;
Chris@753 380 return true;
Chris@753 381 }
gyorgyf@645 382 }
gyorgyf@645 383 }
Chris@127 384
Chris@127 385 return false;
Chris@127 386 }
Chris@127 387
Chris@127 388 bool
Chris@127 389 Pane::selectionIsBeingEdited() const
Chris@127 390 {
Chris@127 391 if (!m_editingSelection.isEmpty()) {
Chris@966 392 if (m_mousePos != m_clickPos &&
Chris@966 393 getFrameForX(m_mousePos.x()) != getFrameForX(m_clickPos.x())) {
Chris@966 394 return true;
Chris@966 395 }
Chris@127 396 }
Chris@127 397 return false;
Chris@127 398 }
Chris@127 399
Chris@127 400 void
Chris@127 401 Pane::setCentreLineVisible(bool visible)
Chris@127 402 {
Chris@127 403 m_centreLineVisible = visible;
Chris@127 404 update();
Chris@127 405 }
Chris@127 406
Chris@127 407 void
Chris@127 408 Pane::paintEvent(QPaintEvent *e)
Chris@127 409 {
Chris@127 410 // Profiler profiler("Pane::paintEvent", true);
Chris@127 411
Chris@127 412 QPainter paint;
Chris@127 413
Chris@127 414 QRect r(rect());
Chris@261 415 if (e) r = e->rect();
Chris@127 416
Chris@127 417 View::paintEvent(e);
Chris@127 418
Chris@127 419 paint.begin(this);
Chris@339 420 setPaintFont(paint);
Chris@338 421
Chris@261 422 if (e) paint.setClipRect(r);
Chris@127 423
Chris@854 424 ViewManager::ToolMode toolMode = ViewManager::NavigateMode;
Chris@854 425 if (m_manager) toolMode = m_manager->getToolModeFor(this);
Chris@259 426
Chris@127 427 if (m_manager &&
Chris@290 428 m_mouseInWidget &&
Chris@259 429 toolMode == ViewManager::MeasureMode) {
Chris@127 430
Chris@835 431 for (LayerList::iterator vi = m_layerStack.end(); vi != m_layerStack.begin(); ) {
Chris@127 432 --vi;
Chris@127 433
Chris@127 434 std::vector<QRect> crosshairExtents;
Chris@127 435
Chris@127 436 if ((*vi)->getCrosshairExtents(this, paint, m_identifyPoint,
Chris@127 437 crosshairExtents)) {
Chris@127 438 (*vi)->paintCrosshairs(this, paint, m_identifyPoint);
Chris@127 439 break;
Chris@127 440 } else if ((*vi)->isLayerOpaque()) {
Chris@127 441 break;
Chris@127 442 }
Chris@127 443 }
Chris@127 444 }
Chris@127 445
Chris@268 446 Layer *topLayer = getTopLayer();
Chris@277 447 bool haveSomeTimeXAxis = false;
Chris@268 448
Chris@258 449 const Model *waveformModel = 0; // just for reporting purposes
Chris@326 450 const Model *workModel = 0;
Chris@326 451
Chris@835 452 for (LayerList::iterator vi = m_layerStack.end(); vi != m_layerStack.begin(); ) {
Chris@127 453 --vi;
Chris@277 454 if (!haveSomeTimeXAxis && (*vi)->hasTimeXAxis()) {
Chris@277 455 haveSomeTimeXAxis = true;
Chris@277 456 }
Chris@127 457 if (dynamic_cast<WaveformLayer *>(*vi)) {
Chris@127 458 waveformModel = (*vi)->getModel();
Chris@326 459 workModel = waveformModel;
Chris@326 460 } else {
Chris@326 461 Model *m = (*vi)->getModel();
Chris@326 462 if (dynamic_cast<WaveFileModel *>(m)) {
Chris@326 463 workModel = m;
Chris@326 464 } else if (m && dynamic_cast<WaveFileModel *>(m->getSourceModel())) {
Chris@326 465 workModel = m->getSourceModel();
Chris@326 466 }
Chris@127 467 }
Chris@326 468
Chris@326 469 if (waveformModel && workModel && haveSomeTimeXAxis) break;
Chris@258 470 }
Chris@127 471
Chris@261 472 m_scaleWidth = 0;
Chris@261 473
Chris@861 474 if (workModel && hasTopLayerTimeXAxis()) {
Chris@759 475 drawModelTimeExtents(r, paint, workModel);
Chris@759 476 }
Chris@759 477
Chris@261 478 if (m_manager && m_manager->shouldShowVerticalScale() && topLayer) {
Chris@261 479 drawVerticalScale(r, topLayer, paint);
Chris@261 480 }
Chris@261 481
Chris@326 482 if (m_identifyFeatures &&
Chris@326 483 m_manager && m_manager->shouldIlluminateLocalFeatures() &&
Chris@326 484 topLayer) {
Chris@261 485 drawFeatureDescription(topLayer, paint);
Chris@261 486 }
Chris@261 487
Chris@908 488 sv_samplerate_t sampleRate = getModelsSampleRate();
Chris@261 489 paint.setBrush(Qt::NoBrush);
Chris@261 490
Chris@261 491 if (m_centreLineVisible &&
Chris@261 492 m_manager &&
Chris@261 493 m_manager->shouldShowCentreLine()) {
Chris@277 494 drawCentreLine(sampleRate, paint, !haveSomeTimeXAxis);
Chris@261 495 }
Chris@261 496
Chris@261 497 paint.setPen(QColor(50, 50, 50));
Chris@261 498
Chris@261 499 if (waveformModel &&
Chris@854 500 sampleRate &&
Chris@261 501 m_manager &&
Chris@261 502 m_manager->shouldShowDuration()) {
Chris@261 503 drawDurationAndRate(r, waveformModel, sampleRate, paint);
Chris@261 504 }
Chris@261 505
Chris@326 506 bool haveWorkTitle = false;
Chris@326 507
Chris@326 508 if (workModel &&
Chris@326 509 m_manager &&
Chris@326 510 m_manager->shouldShowWorkTitle()) {
Chris@326 511 drawWorkTitle(r, paint, workModel);
Chris@326 512 haveWorkTitle = true;
Chris@326 513 }
Chris@326 514
Chris@326 515 if (workModel &&
Chris@320 516 m_manager &&
Chris@320 517 m_manager->getAlignMode()) {
Chris@326 518 drawAlignmentStatus(r, paint, workModel, haveWorkTitle);
Chris@320 519 }
Chris@320 520
Chris@261 521 if (m_manager &&
Chris@261 522 m_manager->shouldShowLayerNames()) {
Chris@261 523 drawLayerNames(r, paint);
Chris@261 524 }
Chris@261 525
Chris@262 526 if (m_shiftPressed && m_clickedInRange &&
Chris@283 527 (toolMode == ViewManager::NavigateMode || m_navigating)) {
Chris@261 528
Chris@261 529 //!!! be nice if this looked a bit more in keeping with the
Chris@261 530 //selection block
Chris@262 531
Chris@262 532 paint.setPen(Qt::blue);
Chris@262 533 //!!! shouldn't use clickPos -- needs to use a clicked frame
Chris@262 534 paint.drawRect(m_clickPos.x(), m_clickPos.y(),
Chris@262 535 m_mousePos.x() - m_clickPos.x(),
Chris@262 536 m_mousePos.y() - m_clickPos.y());
Chris@261 537
Chris@262 538 }
Chris@261 539
Chris@266 540 if (toolMode == ViewManager::MeasureMode && topLayer) {
Chris@272 541 bool showFocus = false;
Chris@272 542 if (!m_manager || !m_manager->isPlaying()) showFocus = true;
Chris@272 543 topLayer->paintMeasurementRects(this, paint, showFocus, m_identifyPoint);
Chris@261 544 }
Chris@261 545
Chris@261 546 if (selectionIsBeingEdited()) {
Chris@261 547 drawEditingSelection(paint);
Chris@261 548 }
Chris@261 549
Chris@261 550 paint.end();
Chris@261 551 }
Chris@261 552
Chris@806 553 int
Chris@276 554 Pane::getVerticalScaleWidth() const
Chris@276 555 {
Chris@276 556 if (m_scaleWidth > 0) return m_scaleWidth;
Chris@276 557 else return 0;
Chris@276 558 }
Chris@276 559
Chris@261 560 void
Chris@261 561 Pane::drawVerticalScale(QRect r, Layer *topLayer, QPainter &paint)
Chris@261 562 {
Chris@258 563 Layer *scaleLayer = 0;
Chris@258 564
Chris@908 565 double min, max;
Chris@261 566 bool log;
Chris@261 567 QString unit;
Chris@258 568
Chris@261 569 // If the top layer has no scale and reports no display
Chris@261 570 // extents, but does report a unit, then the scale should be
Chris@261 571 // drawn from any underlying layer with a scale and that unit.
Chris@261 572 // If the top layer has no scale and no value extents at all,
Chris@261 573 // then the scale should be drawn from any underlying layer
Chris@261 574 // with a scale regardless of unit.
Chris@258 575
Chris@607 576 int sw = topLayer->getVerticalScaleWidth
Chris@607 577 (this, m_manager->shouldShowVerticalColourScale(), paint);
Chris@258 578
Chris@261 579 if (sw > 0) {
Chris@261 580 scaleLayer = topLayer;
Chris@261 581 m_scaleWidth = sw;
Chris@258 582
Chris@261 583 } else {
Chris@258 584
Chris@261 585 bool hasDisplayExtents = topLayer->getDisplayExtents(min, max);
Chris@261 586 bool hasValueExtents = topLayer->getValueExtents(min, max, log, unit);
Chris@261 587
Chris@261 588 if (!hasDisplayExtents) {
Chris@258 589
Chris@261 590 if (!hasValueExtents) {
Chris@258 591
Chris@835 592 for (LayerList::iterator vi = m_layerStack.end();
Chris@835 593 vi != m_layerStack.begin(); ) {
Chris@261 594
Chris@261 595 --vi;
Chris@261 596
Chris@261 597 if ((*vi) == topLayer) continue;
Chris@261 598
Chris@607 599 sw = (*vi)->getVerticalScaleWidth
Chris@607 600 (this, m_manager->shouldShowVerticalColourScale(), paint);
Chris@261 601
Chris@261 602 if (sw > 0) {
Chris@261 603 scaleLayer = *vi;
Chris@261 604 m_scaleWidth = sw;
Chris@261 605 break;
Chris@261 606 }
Chris@261 607 }
Chris@261 608 } else if (unit != "") { // && hasValueExtents && !hasDisplayExtents
Chris@258 609
Chris@261 610 QString requireUnit = unit;
Chris@261 611
Chris@835 612 for (LayerList::iterator vi = m_layerStack.end();
Chris@835 613 vi != m_layerStack.begin(); ) {
Chris@258 614
Chris@261 615 --vi;
Chris@258 616
Chris@261 617 if ((*vi) == topLayer) continue;
Chris@258 618
Chris@261 619 if ((*vi)->getDisplayExtents(min, max)) {
Chris@261 620
Chris@261 621 // search no further than this: if the
Chris@261 622 // scale from this layer isn't suitable,
Chris@261 623 // we'll have to draw no scale (else we'd
Chris@261 624 // risk ending up with the wrong scale)
Chris@261 625
Chris@261 626 if ((*vi)->getValueExtents(min, max, log, unit) &&
Chris@261 627 unit == requireUnit) {
Chris@261 628
Chris@607 629 sw = (*vi)->getVerticalScaleWidth
Chris@607 630 (this, m_manager->shouldShowVerticalColourScale(), paint);
Chris@261 631 if (sw > 0) {
Chris@261 632 scaleLayer = *vi;
Chris@261 633 m_scaleWidth = sw;
Chris@261 634 }
Chris@258 635 }
Chris@261 636 break;
Chris@258 637 }
Chris@258 638 }
Chris@258 639 }
Chris@127 640 }
Chris@258 641 }
Chris@127 642
Chris@258 643 if (!scaleLayer) m_scaleWidth = 0;
Chris@258 644
Chris@258 645 if (m_scaleWidth > 0 && r.left() < m_scaleWidth) {
Chris@127 646
gyorgyf@645 647 // Profiler profiler("Pane::paintEvent - painting vertical scale", true);
gyorgyf@645 648
gyorgyf@645 649 // SVDEBUG << "Pane::paintEvent: calling paint.save() in vertical scale block" << endl;
Chris@258 650 paint.save();
Chris@258 651
Chris@287 652 paint.setPen(getForeground());
Chris@287 653 paint.setBrush(getBackground());
Chris@258 654 paint.drawRect(0, -1, m_scaleWidth, height()+1);
Chris@258 655
Chris@258 656 paint.setBrush(Qt::NoBrush);
Chris@258 657 scaleLayer->paintVerticalScale
Chris@607 658 (this, m_manager->shouldShowVerticalColourScale(),
Chris@607 659 paint, QRect(0, 0, m_scaleWidth, height()));
Chris@258 660
Chris@258 661 paint.restore();
Chris@258 662 }
Chris@261 663 }
Chris@261 664
Chris@261 665 void
Chris@261 666 Pane::drawFeatureDescription(Layer *topLayer, QPainter &paint)
Chris@261 667 {
Chris@261 668 QPoint pos = m_identifyPoint;
Chris@261 669 QString desc = topLayer->getFeatureDescription(this, pos);
gyorgyf@645 670
Chris@261 671 if (desc != "") {
Chris@261 672
Chris@261 673 paint.save();
Chris@261 674
Chris@261 675 int tabStop =
Chris@261 676 paint.fontMetrics().width(tr("Some lengthy prefix:"));
Chris@261 677
Chris@261 678 QRect boundingRect =
Chris@261 679 paint.fontMetrics().boundingRect
Chris@261 680 (rect(),
Chris@261 681 Qt::AlignRight | Qt::AlignTop | Qt::TextExpandTabs,
Chris@261 682 desc, tabStop);
Chris@261 683
Chris@261 684 if (hasLightBackground()) {
Chris@261 685 paint.setPen(Qt::NoPen);
Chris@261 686 paint.setBrush(QColor(250, 250, 250, 200));
Chris@261 687 } else {
Chris@261 688 paint.setPen(Qt::NoPen);
Chris@261 689 paint.setBrush(QColor(50, 50, 50, 200));
Chris@261 690 }
Chris@261 691
Chris@261 692 int extra = paint.fontMetrics().descent();
Chris@261 693 paint.drawRect(width() - boundingRect.width() - 10 - extra,
Chris@261 694 10 - extra,
Chris@261 695 boundingRect.width() + 2 * extra,
Chris@261 696 boundingRect.height() + extra);
Chris@261 697
Chris@261 698 if (hasLightBackground()) {
Chris@261 699 paint.setPen(QColor(150, 20, 0));
Chris@261 700 } else {
Chris@261 701 paint.setPen(QColor(255, 150, 100));
Chris@261 702 }
Chris@261 703
Chris@261 704 QTextOption option;
Chris@261 705 option.setWrapMode(QTextOption::NoWrap);
Chris@261 706 option.setAlignment(Qt::AlignRight | Qt::AlignTop);
Chris@261 707 option.setTabStop(tabStop);
Chris@261 708 paint.drawText(QRectF(width() - boundingRect.width() - 10, 10,
Chris@261 709 boundingRect.width(),
Chris@261 710 boundingRect.height()),
Chris@261 711 desc,
Chris@261 712 option);
Chris@261 713
Chris@261 714 paint.restore();
Chris@261 715 }
Chris@261 716 }
Chris@258 717
Chris@261 718 void
Chris@908 719 Pane::drawCentreLine(sv_samplerate_t sampleRate, QPainter &paint, bool omitLine)
Chris@261 720 {
Chris@880 721 if (omitLine && m_manager->getMainModelSampleRate() == 0) {
Chris@880 722 return;
Chris@880 723 }
Chris@880 724
Chris@261 725 int fontHeight = paint.fontMetrics().height();
Chris@261 726 int fontAscent = paint.fontMetrics().ascent();
Chris@261 727
Chris@261 728 QColor c = QColor(0, 0, 0);
Chris@261 729 if (!hasLightBackground()) {
Chris@261 730 c = QColor(240, 240, 240);
Chris@261 731 }
Chris@277 732
Chris@261 733 paint.setPen(c);
Chris@274 734 int x = width() / 2;
Chris@277 735
Chris@277 736 if (!omitLine) {
Chris@277 737 paint.drawLine(x, 0, x, height() - 1);
Chris@277 738 paint.drawLine(x-1, 1, x+1, 1);
Chris@277 739 paint.drawLine(x-2, 0, x+2, 0);
Chris@277 740 paint.drawLine(x-1, height() - 2, x+1, height() - 2);
Chris@277 741 paint.drawLine(x-2, height() - 1, x+2, height() - 1);
Chris@277 742 }
Chris@261 743
Chris@261 744 paint.setPen(QColor(50, 50, 50));
Chris@261 745
Chris@261 746 int y = height() - fontHeight + fontAscent - 6;
Chris@261 747
Chris@835 748 LayerList::iterator vi = m_layerStack.end();
Chris@261 749
Chris@835 750 if (vi != m_layerStack.begin()) {
gyorgyf@645 751
Chris@261 752 switch ((*--vi)->getPreferredFrameCountPosition()) {
Chris@258 753
Chris@261 754 case Layer::PositionTop:
Chris@261 755 y = fontAscent + 6;
Chris@261 756 break;
Chris@258 757
Chris@261 758 case Layer::PositionMiddle:
Chris@261 759 y = (height() - fontHeight) / 2
Chris@261 760 + fontAscent;
Chris@261 761 break;
Chris@127 762
Chris@261 763 case Layer::PositionBottom:
Chris@261 764 // y already set correctly
Chris@261 765 break;
Chris@127 766 }
Chris@127 767 }
Chris@127 768
Chris@261 769 if (m_manager && m_manager->shouldShowFrameCount()) {
Chris@261 770
Chris@261 771 if (sampleRate) {
Chris@127 772
Chris@261 773 QString text(QString::fromStdString
Chris@261 774 (RealTime::frame2RealTime
Chris@549 775 (m_centreFrame, sampleRate)
Chris@549 776 .toText(true)));
Chris@127 777
Chris@261 778 int tw = paint.fontMetrics().width(text);
Chris@261 779 int x = width()/2 - 4 - tw;
Chris@127 780
Chris@1078 781 PaintAssistant::drawVisibleText(this, paint, x, y, text, PaintAssistant::OutlinedText);
Chris@127 782 }
Chris@261 783
Chris@261 784 QString text = QString("%1").arg(m_centreFrame);
Chris@261 785
Chris@261 786 int x = width()/2 + 4;
Chris@261 787
Chris@1078 788 PaintAssistant::drawVisibleText(this, paint, x, y, text, PaintAssistant::OutlinedText);
Chris@261 789 }
Chris@261 790 }
Chris@127 791
Chris@261 792 void
Chris@759 793 Pane::drawModelTimeExtents(QRect r, QPainter &paint, const Model *model)
Chris@759 794 {
Chris@759 795 int x0 = getXForFrame(model->getStartFrame());
Chris@759 796 int x1 = getXForFrame(model->getEndFrame());
Chris@759 797
Chris@759 798 paint.save();
Chris@759 799
Chris@759 800 QBrush brush;
Chris@759 801
Chris@759 802 if (hasLightBackground()) {
Chris@759 803 brush = QBrush(QColor("#f8f8f8"));
Chris@759 804 paint.setPen(Qt::black);
Chris@759 805 } else {
Chris@759 806 brush = QBrush(QColor("#101010"));
Chris@759 807 paint.setPen(Qt::white);
Chris@759 808 }
Chris@759 809
Chris@759 810 if (x0 > r.x()) {
Chris@759 811 paint.fillRect(0, 0, x0, height(), brush);
Chris@759 812 paint.drawLine(x0, 0, x0, height());
Chris@759 813 }
Chris@759 814
Chris@759 815 if (x1 < r.x() + r.width()) {
Chris@759 816 paint.fillRect(x1, 0, width() - x1, height(), brush);
Chris@759 817 paint.drawLine(x1, 0, x1, height());
Chris@759 818 }
Chris@759 819
Chris@759 820 paint.restore();
Chris@759 821 }
Chris@759 822
Chris@759 823 void
Chris@326 824 Pane::drawAlignmentStatus(QRect r, QPainter &paint, const Model *model,
Chris@326 825 bool down)
Chris@320 826 {
Chris@320 827 const Model *reference = model->getAlignmentReference();
Chris@320 828 /*
Chris@320 829 if (!reference) {
Chris@682 830 cerr << "Pane[" << this << "]::drawAlignmentStatus: No reference" << endl;
Chris@320 831 } else if (reference == model) {
Chris@682 832 cerr << "Pane[" << this << "]::drawAlignmentStatus: This is the reference model" << endl;
Chris@320 833 } else {
Chris@682 834 cerr << "Pane[" << this << "]::drawAlignmentStatus: This is not the reference" << endl;
Chris@320 835 }
Chris@320 836 */
Chris@320 837 QString text;
Chris@320 838 int completion = 100;
Chris@320 839
Chris@320 840 if (reference == model) {
Chris@320 841 text = tr("Reference");
Chris@320 842 } else if (!reference) {
Chris@320 843 text = tr("Unaligned");
Chris@320 844 } else {
Chris@320 845 completion = model->getAlignmentCompletion();
Chris@320 846 if (completion == 0) {
Chris@320 847 text = tr("Unaligned");
Chris@320 848 } else if (completion < 100) {
Chris@320 849 text = tr("Aligning: %1%").arg(completion);
Chris@320 850 } else {
Chris@320 851 text = tr("Aligned");
Chris@320 852 }
Chris@320 853 }
Chris@320 854
Chris@320 855 paint.save();
Chris@320 856 QFont font(paint.font());
Chris@320 857 font.setBold(true);
Chris@320 858 paint.setFont(font);
Chris@326 859 if (completion < 100) paint.setBrush(Qt::red);
Chris@326 860
Chris@326 861 int y = 5;
Chris@326 862 if (down) y += paint.fontMetrics().height();
Chris@326 863 int w = paint.fontMetrics().width(text);
Chris@326 864 int h = paint.fontMetrics().height();
Chris@326 865 if (r.top() > h + y || r.left() > w + m_scaleWidth + 5) {
Chris@326 866 paint.restore();
Chris@326 867 return;
Chris@326 868 }
Chris@320 869
Chris@1078 870 PaintAssistant::drawVisibleText(this, paint, m_scaleWidth + 5,
Chris@1078 871 paint.fontMetrics().ascent() + y, text, PaintAssistant::OutlinedText);
Chris@320 872
Chris@320 873 paint.restore();
Chris@320 874 }
Chris@320 875
Chris@320 876 void
Chris@320 877 Pane::modelAlignmentCompletionChanged()
Chris@320 878 {
Chris@320 879 View::modelAlignmentCompletionChanged();
Chris@320 880 update(QRect(0, 0, 300, 100));
Chris@320 881 }
Chris@320 882
Chris@320 883 void
Chris@326 884 Pane::drawWorkTitle(QRect r, QPainter &paint, const Model *model)
Chris@326 885 {
Chris@326 886 QString title = model->getTitle();
Chris@326 887 QString maker = model->getMaker();
Chris@587 888 //SVDEBUG << "Pane::drawWorkTitle: title=\"" << title//<< "\", maker=\"" << maker << "\"" << endl;
Chris@326 889 if (title == "") return;
Chris@326 890
Chris@326 891 QString text = title;
Chris@326 892 if (maker != "") {
Chris@326 893 text = tr("%1 - %2").arg(title).arg(maker);
Chris@326 894 }
Chris@326 895
Chris@326 896 paint.save();
Chris@326 897 QFont font(paint.font());
Chris@326 898 font.setItalic(true);
Chris@326 899 paint.setFont(font);
Chris@326 900
Chris@326 901 int y = 5;
Chris@326 902 int w = paint.fontMetrics().width(text);
Chris@326 903 int h = paint.fontMetrics().height();
Chris@326 904 if (r.top() > h + y || r.left() > w + m_scaleWidth + 5) {
Chris@326 905 paint.restore();
Chris@326 906 return;
Chris@326 907 }
Chris@326 908
Chris@1078 909 PaintAssistant::drawVisibleText(this, paint, m_scaleWidth + 5,
Chris@1078 910 paint.fontMetrics().ascent() + y, text, PaintAssistant::OutlinedText);
Chris@326 911
Chris@326 912 paint.restore();
Chris@326 913 }
Chris@326 914
Chris@326 915 void
Chris@261 916 Pane::drawLayerNames(QRect r, QPainter &paint)
Chris@261 917 {
Chris@261 918 int fontHeight = paint.fontMetrics().height();
Chris@261 919 int fontAscent = paint.fontMetrics().ascent();
Chris@127 920
Chris@300 921 int lly = height() - 6;
Chris@300 922 if (m_manager->getZoomWheelsEnabled()) {
Chris@300 923 lly -= 20;
Chris@300 924 }
Chris@300 925
Chris@835 926 if (r.y() + r.height() < lly - int(m_layerStack.size()) * fontHeight) {
Chris@261 927 return;
Chris@127 928 }
Chris@127 929
Chris@294 930 QStringList texts;
Chris@299 931 std::vector<QPixmap> pixmaps;
Chris@835 932 for (LayerList::iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
Chris@294 933 texts.push_back((*i)->getLayerPresentationName());
Chris@682 934 // cerr << "Pane " << this << ": Layer presentation name for " << *i << ": "
Chris@682 935 // << texts[texts.size()-1] << endl;
Chris@299 936 pixmaps.push_back((*i)->getLayerPresentationPixmap
Chris@299 937 (QSize(fontAscent, fontAscent)));
Chris@294 938 }
Chris@127 939
Chris@294 940 int maxTextWidth = width() / 3;
Chris@294 941 texts = TextAbbrev::abbreviate(texts, paint.fontMetrics(), maxTextWidth);
Chris@294 942
Chris@261 943 int llx = width() - maxTextWidth - 5;
Chris@261 944 if (m_manager->getZoomWheelsEnabled()) {
Chris@261 945 llx -= 36;
Chris@261 946 }
Chris@261 947
Chris@300 948 if (r.x() + r.width() >= llx - fontAscent - 3) {
gyorgyf@645 949
Chris@802 950 for (int i = 0; i < texts.size(); ++i) {
Chris@299 951
Chris@682 952 // cerr << "Pane "<< this << ": text " << i << ": " << texts[i] << endl;
Chris@261 953
Chris@261 954 if (i + 1 == texts.size()) {
Chris@287 955 paint.setPen(getForeground());
Chris@261 956 }
Chris@261 957
Chris@1078 958 PaintAssistant::drawVisibleText(this, paint, llx,
Chris@261 959 lly - fontHeight + fontAscent,
Chris@1078 960 texts[i], PaintAssistant::OutlinedText);
Chris@299 961
Chris@299 962 if (!pixmaps[i].isNull()) {
Chris@299 963 paint.drawPixmap(llx - fontAscent - 3,
Chris@299 964 lly - fontHeight + (fontHeight-fontAscent)/2,
Chris@299 965 pixmaps[i]);
Chris@299 966 }
Chris@261 967
Chris@261 968 lly -= fontHeight;
Chris@261 969 }
Chris@261 970 }
Chris@261 971 }
Chris@127 972
Chris@261 973 void
Chris@261 974 Pane::drawEditingSelection(QPainter &paint)
Chris@261 975 {
Chris@261 976 int offset = m_mousePos.x() - m_clickPos.x();
Chris@577 977
Chris@908 978 sv_frame_t origStart = m_editingSelection.getStartFrame();
Chris@577 979
Chris@577 980 int p0 = getXForFrame(origStart) + offset;
Chris@261 981 int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset;
Chris@577 982
Chris@261 983 if (m_editingSelectionEdge < 0) {
Chris@261 984 p1 = getXForFrame(m_editingSelection.getEndFrame());
Chris@261 985 } else if (m_editingSelectionEdge > 0) {
Chris@261 986 p0 = getXForFrame(m_editingSelection.getStartFrame());
Chris@127 987 }
Chris@127 988
Chris@908 989 sv_frame_t newStart = getFrameForX(p0);
Chris@908 990 sv_frame_t newEnd = getFrameForX(p1);
Chris@577 991
Chris@261 992 paint.save();
Chris@287 993 paint.setPen(QPen(getForeground(), 2));
Chris@577 994
Chris@577 995 int fontHeight = paint.fontMetrics().height();
Chris@577 996 int fontAscent = paint.fontMetrics().ascent();
Chris@908 997 sv_samplerate_t sampleRate = getModelsSampleRate();
Chris@577 998 QString startText, endText, offsetText;
Chris@577 999 startText = QString("%1").arg(newStart);
Chris@577 1000 endText = QString("%1").arg(newEnd);
Chris@577 1001 offsetText = QString("%1").arg(newStart - origStart);
Chris@577 1002 if (newStart >= origStart) {
Chris@577 1003 offsetText = tr("+%1").arg(offsetText);
Chris@577 1004 }
Chris@577 1005 if (sampleRate) {
Chris@577 1006 startText = QString("%1 / %2")
Chris@577 1007 .arg(QString::fromStdString
Chris@577 1008 (RealTime::frame2RealTime(newStart, sampleRate).toText()))
Chris@577 1009 .arg(startText);
Chris@577 1010 endText = QString("%1 / %2")
Chris@577 1011 .arg(QString::fromStdString
Chris@577 1012 (RealTime::frame2RealTime(newEnd, sampleRate).toText()))
Chris@577 1013 .arg(endText);
Chris@577 1014 offsetText = QString("%1 / %2")
Chris@577 1015 .arg(QString::fromStdString
Chris@577 1016 (RealTime::frame2RealTime(newStart - origStart, sampleRate).toText()))
Chris@577 1017 .arg(offsetText);
Chris@577 1018 if (newStart >= origStart) {
Chris@577 1019 offsetText = tr("+%1").arg(offsetText);
Chris@577 1020 }
Chris@577 1021 }
Chris@1078 1022 PaintAssistant::drawVisibleText(this, paint, p0 + 2, fontAscent + fontHeight + 4, startText, PaintAssistant::OutlinedText);
Chris@1078 1023 PaintAssistant::drawVisibleText(this, paint, p1 + 2, fontAscent + fontHeight + 4, endText, PaintAssistant::OutlinedText);
Chris@1078 1024 PaintAssistant::drawVisibleText(this, paint, p0 + 2, fontAscent + fontHeight*2 + 4, offsetText, PaintAssistant::OutlinedText);
Chris@1078 1025 PaintAssistant::drawVisibleText(this, paint, p1 + 2, fontAscent + fontHeight*2 + 4, offsetText, PaintAssistant::OutlinedText);
Chris@261 1026
Chris@261 1027 //!!! duplicating display policy with View::drawSelections
Chris@261 1028
Chris@261 1029 if (m_editingSelectionEdge < 0) {
Chris@261 1030 paint.drawLine(p0, 1, p1, 1);
Chris@261 1031 paint.drawLine(p0, 0, p0, height());
Chris@261 1032 paint.drawLine(p0, height() - 1, p1, height() - 1);
Chris@261 1033 } else if (m_editingSelectionEdge > 0) {
Chris@261 1034 paint.drawLine(p0, 1, p1, 1);
Chris@261 1035 paint.drawLine(p1, 0, p1, height());
Chris@261 1036 paint.drawLine(p0, height() - 1, p1, height() - 1);
Chris@261 1037 } else {
Chris@261 1038 paint.setBrush(Qt::NoBrush);
Chris@261 1039 paint.drawRect(p0, 1, p1 - p0, height() - 2);
Chris@261 1040 }
Chris@261 1041 paint.restore();
Chris@261 1042 }
Chris@127 1043
Chris@261 1044 void
Chris@261 1045 Pane::drawDurationAndRate(QRect r, const Model *waveformModel,
Chris@908 1046 sv_samplerate_t sampleRate, QPainter &paint)
Chris@261 1047 {
Chris@261 1048 int fontHeight = paint.fontMetrics().height();
Chris@261 1049 int fontAscent = paint.fontMetrics().ascent();
Chris@127 1050
Chris@261 1051 if (r.y() + r.height() < height() - fontHeight - 6) return;
Chris@127 1052
Chris@908 1053 sv_samplerate_t modelRate = waveformModel->getSampleRate();
Chris@908 1054 sv_samplerate_t nativeRate = waveformModel->getNativeRate();
Chris@908 1055 sv_samplerate_t playbackRate = m_manager->getPlaybackSampleRate();
Chris@908 1056 sv_samplerate_t outputRate = m_manager->getOutputSampleRate();
Chris@261 1057
Chris@261 1058 QString srNote = "";
Chris@127 1059
Chris@301 1060 // Show (R) for waveform models that have been resampled or will
Chris@301 1061 // be resampled on playback, and (X) for waveform models that will
Chris@301 1062 // be played at the wrong rate because their rate differs from the
Chris@261 1063 // current playback rate (which is not necessarily that of the
Chris@261 1064 // main model).
Chris@127 1065
Chris@261 1066 if (playbackRate != 0) {
Chris@261 1067 if (modelRate == playbackRate) {
Chris@301 1068 if (modelRate != outputRate || modelRate != nativeRate) {
Chris@301 1069 srNote = " " + tr("(R)");
Chris@301 1070 }
Chris@261 1071 } else {
Chris@261 1072 srNote = " " + tr("(X)");
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@908 1126 Pane::toNewImage(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@908 1165 Pane::getImageSize(sv_frame_t f0, sv_frame_t f1)
Chris@229 1166 {
Chris@229 1167 QSize s = View::getImageSize(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 {
Chris@826 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@826 2274 int dx = e->angleDelta().x();
Chris@826 2275 int dy = e->angleDelta().y();
Chris@826 2276
Chris@826 2277 if (dx == 0 && dy == 0) {
Chris@826 2278 return;
Chris@127 2279 }
Chris@127 2280
Chris@826 2281 int d = dy;
Chris@826 2282 bool horizontal = false;
Chris@826 2283
Chris@826 2284 if (abs(dx) > abs(dy)) {
Chris@826 2285 d = dx;
Chris@826 2286 horizontal = true;
Chris@826 2287 } else if (e->modifiers() & Qt::ControlModifier) {
Chris@826 2288 // treat a vertical wheel as horizontal
Chris@826 2289 horizontal = true;
Chris@826 2290 }
Chris@826 2291
Chris@826 2292 if (e->phase() == Qt::ScrollBegin ||
Chris@826 2293 fabs(d) >= 120 ||
Chris@826 2294 (d > 0 && m_pendingWheelAngle < 0) ||
Chris@826 2295 (d < 0 && m_pendingWheelAngle > 0)) {
Chris@826 2296 m_pendingWheelAngle = d;
Chris@826 2297 } else {
Chris@826 2298 m_pendingWheelAngle += d;
Chris@826 2299 }
Chris@826 2300
Chris@826 2301 if (horizontal && e->pixelDelta().x() != 0) {
Chris@826 2302
Chris@826 2303 // Have fine pixel information: use it
Chris@826 2304
Chris@826 2305 wheelHorizontalFine(e->pixelDelta().x(), e->modifiers());
Chris@826 2306
Chris@826 2307 m_pendingWheelAngle = 0;
Chris@826 2308
Chris@826 2309 } else {
Chris@826 2310
Chris@826 2311 // Coarse wheel information (or vertical zoom, which is
Chris@826 2312 // necessarily coarse itself)
Chris@826 2313
Chris@870 2314 // Sometimes on Linux we're seeing absurdly extreme angles on
Chris@870 2315 // the first wheel event -- discard those entirely
Chris@873 2316 if (abs(m_pendingWheelAngle) >= 600) {
Chris@870 2317 m_pendingWheelAngle = 0;
Chris@870 2318 return;
Chris@870 2319 }
Chris@895 2320
Chris@826 2321 while (abs(m_pendingWheelAngle) >= 120) {
Chris@826 2322
Chris@826 2323 int sign = (m_pendingWheelAngle < 0 ? -1 : 1);
Chris@826 2324
Chris@826 2325 if (horizontal) {
Chris@826 2326 wheelHorizontal(sign, e->modifiers());
Chris@826 2327 } else {
Chris@826 2328 wheelVertical(sign, e->modifiers());
Chris@826 2329 }
Chris@826 2330
Chris@826 2331 m_pendingWheelAngle -= sign * 120;
Chris@826 2332 }
Chris@826 2333 }
Chris@826 2334 }
Chris@826 2335
Chris@826 2336 void
Chris@826 2337 Pane::wheelVertical(int sign, Qt::KeyboardModifiers mods)
Chris@826 2338 {
Chris@826 2339 cerr << "wheelVertical: sign = " << sign << endl;
Chris@826 2340
Chris@826 2341 if (mods & Qt::ShiftModifier) {
Chris@826 2342
Chris@826 2343 // Pan vertically
Chris@826 2344
Chris@826 2345 if (m_vpan) {
Chris@826 2346 m_vpan->scroll(sign > 0);
Chris@826 2347 }
Chris@826 2348
Chris@826 2349 } else if (mods & Qt::AltModifier) {
Chris@826 2350
Chris@826 2351 // Zoom vertically
Chris@826 2352
Chris@826 2353 if (m_vthumb) {
Chris@826 2354 m_vthumb->scroll(sign > 0);
Chris@826 2355 }
Chris@826 2356
Chris@826 2357 } else {
Chris@826 2358
Chris@826 2359 // Zoom in or out
Chris@826 2360
Chris@826 2361 int newZoomLevel = m_zoomLevel;
Chris@826 2362
Chris@826 2363 if (sign > 0) {
Chris@826 2364 if (newZoomLevel <= 2) {
Chris@826 2365 newZoomLevel = 1;
Chris@826 2366 } else {
Chris@826 2367 newZoomLevel = getZoomConstraintBlockSize
Chris@826 2368 (newZoomLevel - 1, ZoomConstraint::RoundDown);
Chris@826 2369 }
Chris@826 2370 } else { // sign < 0
Chris@826 2371 newZoomLevel = getZoomConstraintBlockSize
Chris@826 2372 (newZoomLevel + 1, ZoomConstraint::RoundUp);
Chris@826 2373 }
Chris@826 2374
Chris@826 2375 if (newZoomLevel != m_zoomLevel) {
Chris@826 2376 setZoomLevel(newZoomLevel);
Chris@826 2377 }
Chris@826 2378 }
Chris@826 2379
Chris@826 2380 emit paneInteractedWith();
Chris@826 2381 }
Chris@826 2382
Chris@826 2383 void
Chris@826 2384 Pane::wheelHorizontal(int sign, Qt::KeyboardModifiers mods)
Chris@826 2385 {
Chris@826 2386 cerr << "wheelHorizontal: sign = " << sign << endl;
Chris@127 2387
gyorgyf@645 2388 // Scroll left or right, rapidly
gyorgyf@645 2389
Chris@826 2390 wheelHorizontalFine((width() / 4) * sign, mods);
Chris@826 2391 }
Chris@826 2392
Chris@826 2393 void
Chris@826 2394 Pane::wheelHorizontalFine(int pixels, Qt::KeyboardModifiers)
Chris@826 2395 {
Chris@826 2396 cerr << "wheelHorizontalFine: pixels = " << pixels << endl;
Chris@826 2397
Chris@826 2398 // Scroll left or right by a fixed number of pixels
Chris@826 2399
gyorgyf@645 2400 if (getStartFrame() < 0 &&
gyorgyf@645 2401 getEndFrame() >= getModelsEndFrame()) return;
gyorgyf@645 2402
Chris@826 2403 int delta = (pixels * m_zoomLevel);
Chris@806 2404
Chris@806 2405 if (m_centreFrame < delta) {
gyorgyf@645 2406 setCentreFrame(0);
Chris@806 2407 } else if (m_centreFrame - delta >= getModelsEndFrame()) {
gyorgyf@645 2408 setCentreFrame(getModelsEndFrame());
gyorgyf@645 2409 } else {
gyorgyf@645 2410 setCentreFrame(m_centreFrame - delta);
gyorgyf@645 2411 }
Chris@127 2412
Chris@127 2413 emit paneInteractedWith();
Chris@127 2414 }
Chris@127 2415
Chris@132 2416 void
Chris@132 2417 Pane::horizontalThumbwheelMoved(int value)
Chris@132 2418 {
Chris@137 2419 //!!! dupe with updateHeadsUpDisplay
Chris@137 2420
Chris@132 2421 int count = 0;
Chris@132 2422 int level = 1;
Chris@137 2423
Chris@137 2424
Chris@137 2425 //!!! pull out into function (presumably in View)
Chris@137 2426 bool haveConstraint = false;
Chris@835 2427 for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end();
Chris@137 2428 ++i) {
Chris@137 2429 if ((*i)->getZoomConstraint() && !(*i)->supportsOtherZoomLevels()) {
Chris@137 2430 haveConstraint = true;
Chris@137 2431 break;
Chris@137 2432 }
Chris@132 2433 }
Chris@132 2434
Chris@137 2435 if (haveConstraint) {
Chris@137 2436 while (true) {
Chris@137 2437 if (m_hthumb->getMaximumValue() - value == count) break;
Chris@137 2438 int newLevel = getZoomConstraintBlockSize(level + 1,
Chris@137 2439 ZoomConstraint::RoundUp);
Chris@137 2440 if (newLevel == level) break;
Chris@137 2441 level = newLevel;
Chris@137 2442 if (++count == 50) break;
Chris@137 2443 }
Chris@137 2444 } else {
Chris@137 2445 while (true) {
Chris@137 2446 if (m_hthumb->getMaximumValue() - value == count) break;
Chris@137 2447 int step = level / 10;
Chris@137 2448 int pwr = 0;
Chris@137 2449 while (step > 0) {
Chris@137 2450 ++pwr;
Chris@137 2451 step /= 2;
Chris@137 2452 }
Chris@137 2453 step = 1;
Chris@137 2454 while (pwr > 0) {
Chris@137 2455 step *= 2;
Chris@137 2456 --pwr;
Chris@137 2457 }
Chris@682 2458 // cerr << level << endl;
Chris@137 2459 level += step;
Chris@137 2460 if (++count == 100 || level > 262144) break;
Chris@137 2461 }
Chris@137 2462 }
Chris@137 2463
Chris@682 2464 // cerr << "new level is " << level << endl;
Chris@132 2465 setZoomLevel(level);
Chris@132 2466 }
Chris@132 2467
Chris@132 2468 void
Chris@132 2469 Pane::verticalThumbwheelMoved(int value)
Chris@132 2470 {
Chris@133 2471 Layer *layer = 0;
Chris@133 2472 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1);
Chris@133 2473 if (layer) {
Chris@133 2474 int defaultStep = 0;
Chris@133 2475 int max = layer->getVerticalZoomSteps(defaultStep);
Chris@133 2476 if (max == 0) {
Chris@133 2477 updateHeadsUpDisplay();
Chris@133 2478 return;
Chris@133 2479 }
Chris@133 2480 if (value > max) {
Chris@133 2481 value = max;
Chris@133 2482 }
Chris@133 2483 layer->setVerticalZoomStep(value);
Chris@174 2484 updateVerticalPanner();
Chris@133 2485 }
Chris@132 2486 }
Chris@132 2487
Chris@174 2488 void
Chris@806 2489 Pane::verticalPannerMoved(float , float y0, float , float h)
Chris@174 2490 {
Chris@908 2491 double vmin, vmax, dmin, dmax;
Chris@174 2492 if (!getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) return;
Chris@908 2493 double y1 = y0 + h;
Chris@908 2494 double newmax = vmin + ((1.0 - y0) * (vmax - vmin));
Chris@908 2495 double newmin = vmin + ((1.0 - y1) * (vmax - vmin));
Chris@682 2496 // cerr << "verticalPannerMoved: (" << x0 << "," << y0 << "," << w
Chris@682 2497 // << "," << h << ") -> (" << newmin << "," << newmax << ")" << endl;
Chris@174 2498 setTopLayerDisplayExtents(newmin, newmax);
Chris@174 2499 }
Chris@174 2500
Chris@188 2501 void
Chris@188 2502 Pane::editVerticalPannerExtents()
Chris@188 2503 {
Chris@188 2504 if (!m_vpan || !m_manager || !m_manager->getZoomWheelsEnabled()) return;
Chris@188 2505
Chris@908 2506 double vmin, vmax, dmin, dmax;
Chris@188 2507 QString unit;
Chris@188 2508 if (!getTopLayerDisplayExtents(vmin, vmax, dmin, dmax, &unit)
Chris@188 2509 || vmax == vmin) {
Chris@188 2510 return;
Chris@188 2511 }
Chris@188 2512
Chris@188 2513 RangeInputDialog dialog(tr("Enter new range"),
Chris@188 2514 tr("New vertical display range, from %1 to %2 %4:")
Chris@188 2515 .arg(vmin).arg(vmax).arg(unit),
Chris@908 2516 unit, float(vmin), float(vmax), this);
Chris@908 2517 dialog.setRange(float(dmin), float(dmax));
Chris@188 2518
Chris@188 2519 if (dialog.exec() == QDialog::Accepted) {
Chris@908 2520 float newmin, newmax;
Chris@908 2521 dialog.getRange(newmin, newmax);
Chris@908 2522 setTopLayerDisplayExtents(newmin, newmax);
Chris@188 2523 updateVerticalPanner();
Chris@188 2524 }
Chris@188 2525 }
Chris@188 2526
Chris@312 2527 void
Chris@437 2528 Pane::layerParametersChanged()
Chris@437 2529 {
Chris@437 2530 View::layerParametersChanged();
Chris@437 2531 updateHeadsUpDisplay();
Chris@437 2532 }
Chris@437 2533
Chris@437 2534 void
Chris@312 2535 Pane::dragEnterEvent(QDragEnterEvent *e)
Chris@312 2536 {
Chris@312 2537 QStringList formats(e->mimeData()->formats());
Chris@682 2538 cerr << "dragEnterEvent: format: "
Chris@683 2539 << formats.join(",")
Chris@312 2540 << ", possibleActions: " << e->possibleActions()
Chris@682 2541 << ", proposedAction: " << e->proposedAction() << endl;
Chris@312 2542
Chris@616 2543 if (e->mimeData()->hasFormat("text/uri-list") ||
Chris@616 2544 e->mimeData()->hasFormat("text/plain")) {
Chris@312 2545
Chris@312 2546 if (e->proposedAction() & Qt::CopyAction) {
Chris@312 2547 e->acceptProposedAction();
Chris@312 2548 } else {
Chris@312 2549 e->setDropAction(Qt::CopyAction);
Chris@312 2550 e->accept();
Chris@312 2551 }
Chris@312 2552 }
Chris@312 2553 }
Chris@312 2554
Chris@312 2555 void
Chris@312 2556 Pane::dropEvent(QDropEvent *e)
Chris@312 2557 {
Chris@683 2558 cerr << "dropEvent: text: \"" << e->mimeData()->text()
Chris@682 2559 << "\"" << endl;
Chris@312 2560
Chris@616 2561 if (e->mimeData()->hasFormat("text/uri-list") ||
Chris@616 2562 e->mimeData()->hasFormat("text/plain")) {
Chris@312 2563
Chris@312 2564 if (e->proposedAction() & Qt::CopyAction) {
Chris@312 2565 e->acceptProposedAction();
Chris@312 2566 } else {
Chris@312 2567 e->setDropAction(Qt::CopyAction);
Chris@312 2568 e->accept();
Chris@312 2569 }
Chris@312 2570
Chris@616 2571 if (e->mimeData()->hasFormat("text/uri-list")) {
Chris@616 2572
Chris@616 2573 SVDEBUG << "accepting... data is \"" << e->mimeData()->data("text/uri-list").data() << "\"" << endl;
Chris@312 2574 emit dropAccepted(QString::fromLocal8Bit
Chris@616 2575 (e->mimeData()->data("text/uri-list").data())
Chris@312 2576 .split(QRegExp("[\\r\\n]+"),
Chris@312 2577 QString::SkipEmptyParts));
Chris@312 2578 } else {
Chris@312 2579 emit dropAccepted(QString::fromLocal8Bit
Chris@616 2580 (e->mimeData()->data("text/plain").data()));
Chris@312 2581 }
Chris@312 2582 }
Chris@312 2583 }
Chris@312 2584
Chris@127 2585 bool
Chris@127 2586 Pane::editSelectionStart(QMouseEvent *e)
Chris@127 2587 {
Chris@127 2588 if (!m_identifyFeatures ||
Chris@711 2589 !m_manager ||
Chris@711 2590 m_manager->getToolModeFor(this) != ViewManager::EditMode) {
Chris@711 2591 return false;
Chris@127 2592 }
Chris@127 2593
Chris@127 2594 bool closeToLeft, closeToRight;
Chris@127 2595 Selection s(getSelectionAt(e->x(), closeToLeft, closeToRight));
Chris@127 2596 if (s.isEmpty()) return false;
Chris@127 2597 m_editingSelection = s;
Chris@127 2598 m_editingSelectionEdge = (closeToLeft ? -1 : closeToRight ? 1 : 0);
Chris@127 2599 m_mousePos = e->pos();
Chris@127 2600 return true;
Chris@127 2601 }
Chris@127 2602
Chris@127 2603 bool
Chris@127 2604 Pane::editSelectionDrag(QMouseEvent *e)
Chris@127 2605 {
Chris@127 2606 if (m_editingSelection.isEmpty()) return false;
Chris@127 2607 m_mousePos = e->pos();
Chris@127 2608 update();
Chris@127 2609 return true;
Chris@127 2610 }
Chris@127 2611
Chris@127 2612 bool
Chris@248 2613 Pane::editSelectionEnd(QMouseEvent *)
Chris@127 2614 {
Chris@127 2615 if (m_editingSelection.isEmpty()) return false;
Chris@127 2616
Chris@127 2617 int offset = m_mousePos.x() - m_clickPos.x();
Chris@840 2618 Layer *layer = getInteractionLayer();
Chris@127 2619
Chris@127 2620 if (offset == 0 || !layer) {
Chris@716 2621 m_editingSelection = Selection();
Chris@716 2622 return true;
Chris@127 2623 }
Chris@127 2624
Chris@127 2625 int p0 = getXForFrame(m_editingSelection.getStartFrame()) + offset;
Chris@127 2626 int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset;
Chris@127 2627
Chris@908 2628 sv_frame_t f0 = getFrameForX(p0);
Chris@908 2629 sv_frame_t f1 = getFrameForX(p1);
Chris@127 2630
Chris@127 2631 Selection newSelection(f0, f1);
Chris@127 2632
Chris@127 2633 if (m_editingSelectionEdge == 0) {
gyorgyf@645 2634
Chris@127 2635 CommandHistory::getInstance()->startCompoundOperation
Chris@127 2636 (tr("Drag Selection"), true);
Chris@127 2637
Chris@716 2638 layer->moveSelection(m_editingSelection, f0);
gyorgyf@645 2639
Chris@127 2640 } else {
gyorgyf@645 2641
Chris@127 2642 CommandHistory::getInstance()->startCompoundOperation
Chris@127 2643 (tr("Resize Selection"), true);
Chris@127 2644
Chris@716 2645 if (m_editingSelectionEdge < 0) {
Chris@716 2646 f1 = m_editingSelection.getEndFrame();
Chris@716 2647 } else {
Chris@716 2648 f0 = m_editingSelection.getStartFrame();
Chris@716 2649 }
Chris@716 2650
Chris@716 2651 newSelection = Selection(f0, f1);
Chris@716 2652 layer->resizeSelection(m_editingSelection, newSelection);
Chris@127 2653 }
Chris@127 2654
Chris@127 2655 m_manager->removeSelection(m_editingSelection);
Chris@127 2656 m_manager->addSelection(newSelection);
Chris@127 2657
Chris@127 2658 CommandHistory::getInstance()->endCompoundOperation();
Chris@127 2659
Chris@127 2660 m_editingSelection = Selection();
Chris@127 2661 return true;
Chris@127 2662 }
Chris@127 2663
Chris@127 2664 void
Chris@127 2665 Pane::toolModeChanged()
Chris@127 2666 {
Chris@711 2667 ViewManager::ToolMode mode = m_manager->getToolModeFor(this);
Chris@587 2668 // SVDEBUG << "Pane::toolModeChanged(" << mode << ")" << endl;
Chris@127 2669
Chris@267 2670 if (mode == ViewManager::MeasureMode && !m_measureCursor1) {
Chris@267 2671 m_measureCursor1 = new QCursor(QBitmap(":/icons/measure1cursor.xbm"),
Chris@267 2672 QBitmap(":/icons/measure1mask.xbm"),
Chris@267 2673 15, 14);
Chris@267 2674 m_measureCursor2 = new QCursor(QBitmap(":/icons/measure2cursor.xbm"),
Chris@267 2675 QBitmap(":/icons/measure2mask.xbm"),
Chris@267 2676 16, 17);
Chris@257 2677 }
Chris@257 2678
Chris@127 2679 switch (mode) {
Chris@127 2680
Chris@127 2681 case ViewManager::NavigateMode:
Chris@713 2682 setCursor(Qt::PointingHandCursor);
Chris@713 2683 break;
gyorgyf@645 2684
Chris@127 2685 case ViewManager::SelectMode:
Chris@713 2686 setCursor(Qt::ArrowCursor);
Chris@713 2687 break;
gyorgyf@645 2688
Chris@127 2689 case ViewManager::EditMode:
Chris@713 2690 setCursor(Qt::UpArrowCursor);
Chris@713 2691 break;
gyorgyf@645 2692
Chris@127 2693 case ViewManager::DrawMode:
Chris@713 2694 setCursor(Qt::CrossCursor);
Chris@713 2695 break;
gyorgyf@645 2696
Chris@335 2697 case ViewManager::EraseMode:
Chris@713 2698 setCursor(Qt::CrossCursor);
Chris@713 2699 break;
Chris@257 2700
Chris@257 2701 case ViewManager::MeasureMode:
Chris@267 2702 if (m_measureCursor1) setCursor(*m_measureCursor1);
Chris@713 2703 break;
Chris@713 2704
Chris@713 2705 // GF: NoteEditMode uses the same default cursor as EditMode, but it will change in a context sensitive manner.
gyorgyf@645 2706 case ViewManager::NoteEditMode:
Chris@713 2707 setCursor(Qt::UpArrowCursor);
Chris@713 2708 break;
gyorgyf@645 2709
gyorgyf@645 2710 /*
Chris@127 2711 case ViewManager::TextMode:
gyorgyf@645 2712 setCursor(Qt::IBeamCursor);
gyorgyf@645 2713 break;
Chris@127 2714 */
Chris@127 2715 }
Chris@127 2716 }
Chris@127 2717
Chris@133 2718 void
Chris@133 2719 Pane::zoomWheelsEnabledChanged()
Chris@133 2720 {
Chris@133 2721 updateHeadsUpDisplay();
Chris@133 2722 update();
Chris@133 2723 }
Chris@133 2724
Chris@133 2725 void
Chris@806 2726 Pane::viewZoomLevelChanged(View *v, int z, bool locked)
Chris@133 2727 {
Chris@682 2728 // cerr << "Pane[" << this << "]::zoomLevelChanged (global now "
Chris@682 2729 // << (m_manager ? m_manager->getGlobalZoom() : 0) << ")" << endl;
Chris@192 2730
Chris@224 2731 View::viewZoomLevelChanged(v, z, locked);
Chris@224 2732
Chris@232 2733 if (m_hthumb && !m_hthumb->isVisible()) return;
Chris@224 2734
Chris@222 2735 if (v != this) {
Chris@222 2736 if (!locked || !m_followZoom) return;
Chris@222 2737 }
Chris@222 2738
Chris@133 2739 if (m_manager && m_manager->getZoomWheelsEnabled()) {
Chris@133 2740 updateHeadsUpDisplay();
Chris@133 2741 }
Chris@133 2742 }
Chris@133 2743
Chris@133 2744 void
Chris@133 2745 Pane::propertyContainerSelected(View *v, PropertyContainer *pc)
Chris@133 2746 {
Chris@133 2747 Layer *layer = 0;
Chris@133 2748
Chris@133 2749 if (getLayerCount() > 0) {
Chris@133 2750 layer = getLayer(getLayerCount() - 1);
Chris@133 2751 disconnect(layer, SIGNAL(verticalZoomChanged()),
Chris@133 2752 this, SLOT(verticalZoomChanged()));
Chris@133 2753 }
Chris@133 2754
Chris@133 2755 View::propertyContainerSelected(v, pc);
Chris@133 2756 updateHeadsUpDisplay();
Chris@133 2757
Chris@187 2758 if (m_vthumb) {
Chris@187 2759 RangeMapper *rm = 0;
Chris@187 2760 if (layer) rm = layer->getNewVerticalZoomRangeMapper();
Chris@187 2761 if (rm) m_vthumb->setRangeMapper(rm);
Chris@187 2762 }
Chris@187 2763
Chris@133 2764 if (getLayerCount() > 0) {
Chris@133 2765 layer = getLayer(getLayerCount() - 1);
Chris@133 2766 connect(layer, SIGNAL(verticalZoomChanged()),
Chris@133 2767 this, SLOT(verticalZoomChanged()));
Chris@133 2768 }
Chris@133 2769 }
Chris@133 2770
Chris@133 2771 void
Chris@133 2772 Pane::verticalZoomChanged()
Chris@133 2773 {
Chris@133 2774 Layer *layer = 0;
Chris@133 2775
Chris@133 2776 if (getLayerCount() > 0) {
Chris@133 2777
Chris@133 2778 layer = getLayer(getLayerCount() - 1);
Chris@133 2779
Chris@133 2780 if (m_vthumb && m_vthumb->isVisible()) {
Chris@133 2781 m_vthumb->setValue(layer->getCurrentVerticalZoomStep());
Chris@133 2782 }
Chris@133 2783 }
Chris@133 2784 }
Chris@133 2785
Chris@189 2786 void
Chris@189 2787 Pane::updateContextHelp(const QPoint *pos)
Chris@189 2788 {
Chris@189 2789 QString help = "";
Chris@189 2790
Chris@189 2791 if (m_clickedInRange) {
Chris@189 2792 emit contextHelpChanged("");
Chris@189 2793 return;
Chris@189 2794 }
Chris@189 2795
Chris@189 2796 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@711 2797 if (m_manager) mode = m_manager->getToolModeFor(this);
Chris@189 2798
Chris@189 2799 bool editable = false;
Chris@840 2800 Layer *layer = getInteractionLayer();
Chris@189 2801 if (layer && layer->isLayerEditable()) {
Chris@189 2802 editable = true;
Chris@189 2803 }
Chris@189 2804
Chris@189 2805 if (mode == ViewManager::NavigateMode) {
Chris@189 2806
Chris@189 2807 help = tr("Click and drag to navigate");
Chris@189 2808
Chris@189 2809 } else if (mode == ViewManager::SelectMode) {
Chris@189 2810
Chris@217 2811 if (!hasTopLayerTimeXAxis()) return;
Chris@217 2812
Chris@189 2813 bool haveSelection = (m_manager && !m_manager->getSelections().empty());
Chris@189 2814
Chris@189 2815 if (haveSelection) {
Chris@597 2816 #ifdef Q_OS_MAC
Chris@597 2817 if (editable) {
Chris@597 2818 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 2819 } else {
Chris@597 2820 help = tr("Click and drag to select a range; hold Cmd for multi-select; middle-click and drag to navigate");
Chris@597 2821 }
Chris@597 2822 #else
Chris@189 2823 if (editable) {
Chris@189 2824 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 2825 } else {
Chris@189 2826 help = tr("Click and drag to select a range; hold Ctrl for multi-select; middle-click and drag to navigate");
Chris@189 2827 }
Chris@597 2828 #endif
Chris@189 2829
Chris@189 2830 if (pos) {
Chris@189 2831 bool closeToLeft = false, closeToRight = false;
Chris@189 2832 Selection selection = getSelectionAt(pos->x(), closeToLeft, closeToRight);
Chris@189 2833 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) {
Chris@189 2834
Chris@189 2835 help = tr("Click and drag to move the selection boundary");
Chris@189 2836 }
Chris@189 2837 }
Chris@189 2838 } else {
Chris@189 2839 if (editable) {
Chris@189 2840 help = tr("Click and drag to select a range; hold Shift to avoid snapping to items; middle-click to navigate");
Chris@189 2841 } else {
Chris@189 2842 help = tr("Click and drag to select a range; middle-click and drag to navigate");
Chris@189 2843 }
Chris@189 2844 }
Chris@189 2845
Chris@189 2846 } else if (mode == ViewManager::DrawMode) {
Chris@189 2847
Chris@189 2848 //!!! could call through to a layer function to find out exact meaning
Chris@713 2849 if (editable) {
Chris@189 2850 help = tr("Click to add a new item in the active layer");
Chris@189 2851 }
Chris@335 2852
Chris@335 2853 } else if (mode == ViewManager::EraseMode) {
Chris@335 2854
Chris@335 2855 //!!! could call through to a layer function to find out exact meaning
Chris@713 2856 if (editable) {
Chris@335 2857 help = tr("Click to erase an item from the active layer");
Chris@335 2858 }
Chris@189 2859
Chris@189 2860 } else if (mode == ViewManager::EditMode) {
Chris@189 2861
Chris@189 2862 //!!! could call through to layer
Chris@713 2863 if (editable) {
Chris@551 2864 help = tr("Click and drag an item in the active layer to move it; hold Shift to override initial resistance");
Chris@189 2865 if (pos) {
Chris@189 2866 bool closeToLeft = false, closeToRight = false;
Chris@189 2867 Selection selection = getSelectionAt(pos->x(), closeToLeft, closeToRight);
Chris@189 2868 if (!selection.isEmpty()) {
Chris@189 2869 help = tr("Click and drag to move all items in the selected range");
Chris@189 2870 }
Chris@189 2871 }
Chris@189 2872 }
Chris@189 2873 }
Chris@189 2874
Chris@189 2875 emit contextHelpChanged(help);
Chris@189 2876 }
Chris@189 2877
Chris@189 2878 void
Chris@189 2879 Pane::mouseEnteredWidget()
Chris@189 2880 {
Chris@189 2881 QWidget *w = dynamic_cast<QWidget *>(sender());
Chris@189 2882 if (!w) return;
Chris@189 2883
Chris@189 2884 if (w == m_vpan) {
Chris@189 2885 emit contextHelpChanged(tr("Click and drag to adjust the visible range of the vertical scale"));
Chris@189 2886 } else if (w == m_vthumb) {
Chris@189 2887 emit contextHelpChanged(tr("Click and drag to adjust the vertical zoom level"));
Chris@189 2888 } else if (w == m_hthumb) {
Chris@189 2889 emit contextHelpChanged(tr("Click and drag to adjust the horizontal zoom level"));
Chris@189 2890 } else if (w == m_reset) {
Chris@189 2891 emit contextHelpChanged(tr("Reset horizontal and vertical zoom levels to their defaults"));
Chris@189 2892 }
Chris@189 2893 }
Chris@189 2894
Chris@189 2895 void
Chris@189 2896 Pane::mouseLeftWidget()
Chris@189 2897 {
Chris@189 2898 emit contextHelpChanged("");
Chris@189 2899 }
Chris@189 2900
Chris@316 2901 void
Chris@316 2902 Pane::toXml(QTextStream &stream,
Chris@316 2903 QString indent, QString extraAttributes) const
Chris@127 2904 {
Chris@316 2905 View::toXml
Chris@316 2906 (stream, indent,
gyorgyf@645 2907 QString("type=\"pane\" centreLineVisible=\"%1\" height=\"%2\" %3")
gyorgyf@645 2908 .arg(m_centreLineVisible).arg(height()).arg(extraAttributes));
Chris@127 2909 }
Chris@127 2910
Chris@127 2911