annotate view/Pane.cpp @ 1064:77564d4fff43 spectrogram-minor-refactor

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