annotate view/Pane.cpp @ 1269:f2894944c6b8

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