annotate view/Pane.cpp @ 640:c6d705bf1672

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