annotate view/Pane.cpp @ 590:241929c5d57c sonification

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