annotate view/Pane.cpp @ 607:5b72899d692b

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