annotate view/Pane.cpp @ 1363:bbeffb29bf09

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