annotate view/Pane.cpp @ 561:aced8ec09bc8

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