annotate view/Pane.cpp @ 854:c17719e488c9

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