annotate view/Pane.cpp @ 333:e74b56f07c73

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