annotate view/Pane.cpp @ 1024:3bce4c45b681 spectrogram-minor-refactor

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