annotate view/Pane.cpp @ 312:6de6f78b13a1

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