annotate view/Pane.cpp @ 738:d26545a2a02d tonioni

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