annotate view/Pane.cpp @ 317:e251c3599ea8

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