annotate view/Pane.cpp @ 583:4c484636d5ec

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