annotate view/Pane.cpp @ 299:5c59c433b358

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