annotate view/Pane.cpp @ 473:4f4f943bfdfc

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