annotate view/Pane.cpp @ 150:b1a3a9400284

* Add a bit of resistance to pane dragging so as to make it harder to inadvertently drag in the other axis from the one you intended
author Chris Cannam
date Fri, 22 Sep 2006 16:46:10 +0000
parents 4d132a06db9b
children 30d624900564
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@127 7 This file copyright 2006 Chris Cannam.
Chris@127 8
Chris@127 9 This program is free software; you can redistribute it and/or
Chris@127 10 modify it under the terms of the GNU General Public License as
Chris@127 11 published by the Free Software Foundation; either version 2 of the
Chris@127 12 License, or (at your option) any later version. See the file
Chris@127 13 COPYING included with this distribution for more information.
Chris@127 14 */
Chris@127 15
Chris@128 16 #include "Pane.h"
Chris@128 17 #include "layer/Layer.h"
Chris@128 18 #include "data/model/Model.h"
Chris@127 19 #include "base/ZoomConstraint.h"
Chris@127 20 #include "base/RealTime.h"
Chris@127 21 #include "base/Profiler.h"
Chris@128 22 #include "ViewManager.h"
Chris@127 23 #include "base/CommandHistory.h"
Chris@127 24 #include "layer/WaveformLayer.h"
Chris@127 25
Chris@127 26 #include <QPaintEvent>
Chris@127 27 #include <QPainter>
Chris@127 28 #include <iostream>
Chris@127 29 #include <cmath>
Chris@127 30
Chris@133 31 //!!! for HUD -- pull out into a separate class
Chris@133 32 #include <QFrame>
Chris@133 33 #include <QGridLayout>
Chris@133 34 #include <QPushButton>
Chris@133 35 #include "widgets/Thumbwheel.h"
Chris@133 36
Chris@127 37 using std::cerr;
Chris@127 38 using std::endl;
Chris@127 39
Chris@127 40 Pane::Pane(QWidget *w) :
Chris@127 41 View(w, true),
Chris@127 42 m_identifyFeatures(false),
Chris@127 43 m_clickedInRange(false),
Chris@127 44 m_shiftPressed(false),
Chris@127 45 m_ctrlPressed(false),
Chris@127 46 m_navigating(false),
Chris@127 47 m_resizing(false),
Chris@133 48 m_centreLineVisible(true),
Chris@133 49 m_headsUpDisplay(0)
Chris@127 50 {
Chris@127 51 setObjectName("Pane");
Chris@127 52 setMouseTracking(true);
Chris@133 53
Chris@133 54 updateHeadsUpDisplay();
Chris@133 55 }
Chris@133 56
Chris@133 57 void
Chris@133 58 Pane::updateHeadsUpDisplay()
Chris@133 59 {
Chris@132 60 /*
Chris@132 61 int count = 0;
Chris@132 62 int currentLevel = 1;
Chris@132 63 int level = 1;
Chris@132 64 while (true) {
Chris@132 65 if (getZoomLevel() == level) currentLevel = count;
Chris@132 66 int newLevel = getZoomConstraintBlockSize(level + 1,
Chris@132 67 ZoomConstraint::RoundUp);
Chris@132 68 if (newLevel == level) break;
Chris@132 69 if (newLevel == 131072) break; //!!! just because
Chris@132 70 level = newLevel;
Chris@132 71 ++count;
Chris@132 72 }
Chris@132 73
Chris@132 74 std::cerr << "Have " << count+1 << " zoom levels" << std::endl;
Chris@132 75 */
Chris@133 76
Chris@133 77 if (!m_headsUpDisplay) {
Chris@133 78
Chris@133 79 m_headsUpDisplay = new QFrame(this);
Chris@133 80
Chris@133 81 QGridLayout *layout = new QGridLayout;
Chris@133 82 layout->setMargin(0);
Chris@133 83 layout->setSpacing(0);
Chris@133 84 m_headsUpDisplay->setLayout(layout);
Chris@133 85
Chris@133 86 m_hthumb = new Thumbwheel(Qt::Horizontal);
Chris@133 87 layout->addWidget(m_hthumb, 1, 0);
Chris@133 88 m_hthumb->setFixedWidth(70);
Chris@133 89 m_hthumb->setFixedHeight(16);
Chris@133 90 m_hthumb->setDefaultValue(0);
Chris@133 91 connect(m_hthumb, SIGNAL(valueChanged(int)), this,
Chris@133 92 SLOT(horizontalThumbwheelMoved(int)));
Chris@133 93
Chris@133 94 m_vthumb = new Thumbwheel(Qt::Vertical);
Chris@133 95 layout->addWidget(m_vthumb, 0, 1);
Chris@133 96 m_vthumb->setFixedWidth(16);
Chris@133 97 m_vthumb->setFixedHeight(70);
Chris@133 98 connect(m_vthumb, SIGNAL(valueChanged(int)), this,
Chris@133 99 SLOT(verticalThumbwheelMoved(int)));
Chris@133 100
Chris@133 101 QPushButton *reset = new QPushButton;
Chris@133 102 reset->setFixedHeight(16);
Chris@133 103 reset->setFixedWidth(16);
Chris@133 104 layout->addWidget(reset, 1, 1);
Chris@133 105 connect(reset, SIGNAL(clicked()), m_hthumb, SLOT(resetToDefault()));
Chris@133 106 connect(reset, SIGNAL(clicked()), m_vthumb, SLOT(resetToDefault()));
Chris@133 107 }
Chris@133 108
Chris@133 109 int count = 0;
Chris@133 110 int current = 0;
Chris@133 111 int level = 1;
Chris@133 112
Chris@137 113 //!!! pull out into function (presumably in View)
Chris@137 114 bool haveConstraint = false;
Chris@137 115 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end();
Chris@137 116 ++i) {
Chris@137 117 if ((*i)->getZoomConstraint() && !(*i)->supportsOtherZoomLevels()) {
Chris@137 118 haveConstraint = true;
Chris@137 119 break;
Chris@137 120 }
Chris@137 121 }
Chris@137 122
Chris@137 123 if (haveConstraint) {
Chris@137 124 while (true) {
Chris@137 125 if (getZoomLevel() == level) current = count;
Chris@137 126 int newLevel = getZoomConstraintBlockSize(level + 1,
Chris@137 127 ZoomConstraint::RoundUp);
Chris@137 128 if (newLevel == level) break;
Chris@137 129 level = newLevel;
Chris@137 130 if (++count == 50) break;
Chris@137 131 }
Chris@137 132 } else {
Chris@137 133 // if we have no particular constraints, we can really spread out
Chris@137 134 while (true) {
Chris@137 135 if (getZoomLevel() >= level) current = count;
Chris@137 136 int step = level / 10;
Chris@137 137 int pwr = 0;
Chris@137 138 while (step > 0) {
Chris@137 139 ++pwr;
Chris@137 140 step /= 2;
Chris@137 141 }
Chris@137 142 step = 1;
Chris@137 143 while (pwr > 0) {
Chris@137 144 step *= 2;
Chris@137 145 --pwr;
Chris@137 146 }
Chris@137 147 std::cerr << level << std::endl;
Chris@137 148 level += step;
Chris@137 149 if (++count == 100 || level > 262144) break;
Chris@137 150 }
Chris@133 151 }
Chris@133 152
Chris@133 153 // std::cerr << "Have " << count << " zoom levels" << std::endl;
Chris@133 154
Chris@133 155 m_hthumb->setMinimumValue(0);
Chris@133 156 m_hthumb->setMaximumValue(count);
Chris@133 157 m_hthumb->setValue(count - current);
Chris@133 158
Chris@133 159 // std::cerr << "set value to " << count-current << std::endl;
Chris@133 160
Chris@133 161 // std::cerr << "default value is " << m_hthumb->getDefaultValue() << std::endl;
Chris@133 162
Chris@133 163 if (count != 50 && m_hthumb->getDefaultValue() == 0) {
Chris@133 164 m_hthumb->setDefaultValue(count - current);
Chris@133 165 // std::cerr << "set default value to " << m_hthumb->getDefaultValue() << std::endl;
Chris@133 166 }
Chris@133 167
Chris@133 168 Layer *layer = 0;
Chris@133 169 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1);
Chris@133 170 if (layer) {
Chris@133 171 int defaultStep = 0;
Chris@133 172 int max = layer->getVerticalZoomSteps(defaultStep);
Chris@133 173 if (max == 0) {
Chris@133 174 m_vthumb->hide();
Chris@133 175 } else {
Chris@133 176 m_vthumb->show();
Chris@133 177 m_vthumb->setMinimumValue(0);
Chris@133 178 m_vthumb->setMaximumValue(max);
Chris@133 179 m_vthumb->setDefaultValue(defaultStep);
Chris@133 180 m_vthumb->setValue(layer->getCurrentVerticalZoomStep());
Chris@135 181
Chris@135 182 std::cerr << "Vertical thumbwheel: min 0, max " << max
Chris@135 183 << ", default " << defaultStep << ", value "
Chris@135 184 << m_vthumb->getValue() << std::endl;
Chris@135 185
Chris@133 186 }
Chris@133 187 }
Chris@133 188
Chris@133 189 if (m_manager && m_manager->getZoomWheelsEnabled() &&
Chris@133 190 width() > 120 && height() > 100) {
Chris@133 191 if (m_vthumb->isVisible()) {
Chris@133 192 m_headsUpDisplay->move(width() - 86, height() - 86);
Chris@133 193 } else {
Chris@133 194 m_headsUpDisplay->move(width() - 86, height() - 51);
Chris@133 195 }
Chris@133 196 if (!m_headsUpDisplay->isVisible()) {
Chris@133 197 m_headsUpDisplay->show();
Chris@133 198 connect(m_manager, SIGNAL(zoomLevelChanged()),
Chris@133 199 this, SLOT(zoomLevelChanged()));
Chris@133 200 }
Chris@133 201 } else {
Chris@133 202 m_headsUpDisplay->hide();
Chris@133 203 if (m_manager) {
Chris@133 204 disconnect(m_manager, SIGNAL(zoomLevelChanged()),
Chris@133 205 this, SLOT(zoomLevelChanged()));
Chris@133 206 }
Chris@133 207 }
Chris@127 208 }
Chris@127 209
Chris@127 210 bool
Chris@127 211 Pane::shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos) const
Chris@127 212 {
Chris@127 213 QPoint discard;
Chris@127 214 bool b0, b1;
Chris@127 215
Chris@127 216 if (layer == getSelectedLayer() &&
Chris@127 217 !shouldIlluminateLocalSelection(discard, b0, b1)) {
Chris@127 218
Chris@127 219 pos = m_identifyPoint;
Chris@127 220 return m_identifyFeatures;
Chris@127 221 }
Chris@127 222
Chris@127 223 return false;
Chris@127 224 }
Chris@127 225
Chris@127 226 bool
Chris@127 227 Pane::shouldIlluminateLocalSelection(QPoint &pos,
Chris@127 228 bool &closeToLeft,
Chris@127 229 bool &closeToRight) const
Chris@127 230 {
Chris@127 231 if (m_identifyFeatures &&
Chris@127 232 m_manager &&
Chris@127 233 m_manager->getToolMode() == ViewManager::EditMode &&
Chris@127 234 !m_manager->getSelections().empty() &&
Chris@127 235 !selectionIsBeingEdited()) {
Chris@127 236
Chris@127 237 Selection s(getSelectionAt(m_identifyPoint.x(),
Chris@127 238 closeToLeft, closeToRight));
Chris@127 239
Chris@127 240 if (!s.isEmpty()) {
Chris@127 241 if (getSelectedLayer() && getSelectedLayer()->isLayerEditable()) {
Chris@127 242
Chris@127 243 pos = m_identifyPoint;
Chris@127 244 return true;
Chris@127 245 }
Chris@127 246 }
Chris@127 247 }
Chris@127 248
Chris@127 249 return false;
Chris@127 250 }
Chris@127 251
Chris@127 252 bool
Chris@127 253 Pane::selectionIsBeingEdited() const
Chris@127 254 {
Chris@127 255 if (!m_editingSelection.isEmpty()) {
Chris@127 256 if (m_mousePos != m_clickPos &&
Chris@127 257 getFrameForX(m_mousePos.x()) != getFrameForX(m_clickPos.x())) {
Chris@127 258 return true;
Chris@127 259 }
Chris@127 260 }
Chris@127 261 return false;
Chris@127 262 }
Chris@127 263
Chris@127 264 void
Chris@127 265 Pane::setCentreLineVisible(bool visible)
Chris@127 266 {
Chris@127 267 m_centreLineVisible = visible;
Chris@127 268 update();
Chris@127 269 }
Chris@127 270
Chris@127 271 void
Chris@127 272 Pane::paintEvent(QPaintEvent *e)
Chris@127 273 {
Chris@127 274 // Profiler profiler("Pane::paintEvent", true);
Chris@127 275
Chris@127 276 QPainter paint;
Chris@127 277
Chris@127 278 QRect r(rect());
Chris@127 279
Chris@127 280 if (e) {
Chris@127 281 r = e->rect();
Chris@127 282 }
Chris@127 283 /*
Chris@127 284 paint.begin(this);
Chris@127 285 paint.setClipRect(r);
Chris@127 286
Chris@127 287 if (hasLightBackground()) {
Chris@127 288 paint.setPen(Qt::white);
Chris@127 289 paint.setBrush(Qt::white);
Chris@127 290 } else {
Chris@127 291 paint.setPen(Qt::black);
Chris@127 292 paint.setBrush(Qt::black);
Chris@127 293 }
Chris@127 294 paint.drawRect(r);
Chris@127 295
Chris@127 296 paint.end();
Chris@127 297 */
Chris@127 298 View::paintEvent(e);
Chris@127 299
Chris@127 300 paint.begin(this);
Chris@127 301
Chris@127 302 if (e) {
Chris@127 303 paint.setClipRect(r);
Chris@127 304 }
Chris@127 305
Chris@127 306 const Model *waveformModel = 0; // just for reporting purposes
Chris@127 307 int verticalScaleWidth = 0;
Chris@127 308
Chris@127 309 int fontHeight = paint.fontMetrics().height();
Chris@127 310 int fontAscent = paint.fontMetrics().ascent();
Chris@127 311
Chris@127 312 if (m_manager &&
Chris@127 313 !m_manager->isPlaying() &&
Chris@127 314 m_manager->getToolMode() == ViewManager::SelectMode) {
Chris@127 315
Chris@127 316 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
Chris@127 317 --vi;
Chris@127 318
Chris@127 319 std::vector<QRect> crosshairExtents;
Chris@127 320
Chris@127 321 if ((*vi)->getCrosshairExtents(this, paint, m_identifyPoint,
Chris@127 322 crosshairExtents)) {
Chris@127 323 (*vi)->paintCrosshairs(this, paint, m_identifyPoint);
Chris@127 324 break;
Chris@127 325 } else if ((*vi)->isLayerOpaque()) {
Chris@127 326 break;
Chris@127 327 }
Chris@127 328 }
Chris@127 329 }
Chris@127 330
Chris@127 331 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
Chris@127 332 --vi;
Chris@127 333
Chris@127 334 if (dynamic_cast<WaveformLayer *>(*vi)) {
Chris@127 335 waveformModel = (*vi)->getModel();
Chris@127 336 }
Chris@127 337
Chris@127 338 if (!m_manager ||
Chris@127 339 m_manager->getOverlayMode() == ViewManager::NoOverlays) {
Chris@127 340 break;
Chris@127 341 }
Chris@127 342
Chris@127 343 verticalScaleWidth = (*vi)->getVerticalScaleWidth(this, paint);
Chris@127 344
Chris@127 345 if (verticalScaleWidth > 0 && r.left() < verticalScaleWidth) {
Chris@127 346
Chris@127 347 // Profiler profiler("Pane::paintEvent - painting vertical scale", true);
Chris@127 348
Chris@127 349 // std::cerr << "Pane::paintEvent: calling paint.save() in vertical scale block" << std::endl;
Chris@127 350 paint.save();
Chris@127 351
Chris@127 352 paint.setPen(Qt::black);
Chris@127 353 paint.setBrush(Qt::white);
Chris@127 354 paint.drawRect(0, -1, verticalScaleWidth, height()+1);
Chris@127 355
Chris@127 356 paint.setBrush(Qt::NoBrush);
Chris@127 357 (*vi)->paintVerticalScale
Chris@127 358 (this, paint, QRect(0, 0, verticalScaleWidth, height()));
Chris@127 359
Chris@127 360 paint.restore();
Chris@127 361 }
Chris@127 362
Chris@127 363 if (m_identifyFeatures) {
Chris@127 364
Chris@127 365 QPoint pos = m_identifyPoint;
Chris@127 366 QString desc = (*vi)->getFeatureDescription(this, pos);
Chris@127 367
Chris@127 368 if (desc != "") {
Chris@127 369
Chris@127 370 paint.save();
Chris@127 371
Chris@127 372 int tabStop =
Chris@127 373 paint.fontMetrics().width(tr("Some lengthy prefix:"));
Chris@127 374
Chris@127 375 QRect boundingRect =
Chris@127 376 paint.fontMetrics().boundingRect
Chris@127 377 (rect(),
Chris@127 378 Qt::AlignRight | Qt::AlignTop | Qt::TextExpandTabs,
Chris@127 379 desc, tabStop);
Chris@127 380
Chris@127 381 if (hasLightBackground()) {
Chris@127 382 paint.setPen(Qt::NoPen);
Chris@127 383 paint.setBrush(QColor(250, 250, 250, 200));
Chris@127 384 } else {
Chris@127 385 paint.setPen(Qt::NoPen);
Chris@127 386 paint.setBrush(QColor(50, 50, 50, 200));
Chris@127 387 }
Chris@127 388
Chris@127 389 int extra = paint.fontMetrics().descent();
Chris@127 390 paint.drawRect(width() - boundingRect.width() - 10 - extra,
Chris@127 391 10 - extra,
Chris@127 392 boundingRect.width() + 2 * extra,
Chris@127 393 boundingRect.height() + extra);
Chris@127 394
Chris@127 395 if (hasLightBackground()) {
Chris@127 396 paint.setPen(QColor(150, 20, 0));
Chris@127 397 } else {
Chris@127 398 paint.setPen(QColor(255, 150, 100));
Chris@127 399 }
Chris@127 400
Chris@127 401 QTextOption option;
Chris@127 402 option.setWrapMode(QTextOption::NoWrap);
Chris@127 403 option.setAlignment(Qt::AlignRight | Qt::AlignTop);
Chris@127 404 option.setTabStop(tabStop);
Chris@127 405 paint.drawText(QRectF(width() - boundingRect.width() - 10, 10,
Chris@127 406 boundingRect.width(),
Chris@127 407 boundingRect.height()),
Chris@127 408 desc,
Chris@127 409 option);
Chris@127 410
Chris@127 411 paint.restore();
Chris@127 412 }
Chris@127 413 }
Chris@127 414
Chris@127 415 break;
Chris@127 416 }
Chris@127 417
Chris@127 418 int sampleRate = getModelsSampleRate();
Chris@127 419 paint.setBrush(Qt::NoBrush);
Chris@127 420
Chris@127 421 if (m_centreLineVisible) {
Chris@127 422
Chris@127 423 if (hasLightBackground()) {
Chris@127 424 paint.setPen(QColor(50, 50, 50));
Chris@127 425 } else {
Chris@127 426 paint.setPen(QColor(200, 200, 200));
Chris@127 427 }
Chris@127 428 paint.drawLine(width() / 2, 0, width() / 2, height() - 1);
Chris@127 429
Chris@127 430 paint.setPen(QColor(50, 50, 50));
Chris@127 431
Chris@127 432 int y = height() - fontHeight
Chris@127 433 + fontAscent - 6;
Chris@127 434
Chris@127 435 LayerList::iterator vi = m_layers.end();
Chris@127 436
Chris@127 437 if (vi != m_layers.begin()) {
Chris@127 438
Chris@127 439 switch ((*--vi)->getPreferredFrameCountPosition()) {
Chris@127 440
Chris@127 441 case Layer::PositionTop:
Chris@127 442 y = fontAscent + 6;
Chris@127 443 break;
Chris@127 444
Chris@127 445 case Layer::PositionMiddle:
Chris@127 446 y = (height() - fontHeight) / 2
Chris@127 447 + fontAscent;
Chris@127 448 break;
Chris@127 449
Chris@127 450 case Layer::PositionBottom:
Chris@127 451 // y already set correctly
Chris@127 452 break;
Chris@127 453 }
Chris@127 454 }
Chris@127 455
Chris@127 456 if (m_manager &&
Chris@127 457 m_manager->getOverlayMode() != ViewManager::NoOverlays) {
Chris@127 458
Chris@127 459 if (sampleRate) {
Chris@127 460
Chris@127 461 QString text(QString::fromStdString
Chris@127 462 (RealTime::frame2RealTime
Chris@127 463 (m_centreFrame, sampleRate).toText(true)));
Chris@127 464
Chris@127 465 int tw = paint.fontMetrics().width(text);
Chris@127 466 int x = width()/2 - 4 - tw;
Chris@127 467
Chris@127 468 drawVisibleText(paint, x, y, text, OutlinedText);
Chris@127 469 }
Chris@127 470
Chris@127 471 QString text = QString("%1").arg(m_centreFrame);
Chris@127 472
Chris@127 473 int tw = paint.fontMetrics().width(text);
Chris@127 474 int x = width()/2 + 4;
Chris@127 475
Chris@127 476 drawVisibleText(paint, x, y, text, OutlinedText);
Chris@127 477 }
Chris@127 478
Chris@127 479 } else {
Chris@127 480
Chris@127 481 paint.setPen(QColor(50, 50, 50));
Chris@127 482 }
Chris@127 483
Chris@127 484 if (waveformModel &&
Chris@127 485 m_manager &&
Chris@127 486 m_manager->getOverlayMode() != ViewManager::NoOverlays &&
Chris@127 487 r.y() + r.height() >= height() - fontHeight - 6) {
Chris@127 488
Chris@150 489 size_t modelRate = waveformModel->getSampleRate();
Chris@127 490 size_t mainModelRate = m_manager->getMainModelSampleRate();
Chris@127 491 size_t playbackRate = m_manager->getPlaybackSampleRate();
Chris@127 492
Chris@127 493 QString srNote = "";
Chris@127 494
Chris@127 495 // Show (R) for waveform models that will be resampled on
Chris@127 496 // playback, and (X) for waveform models that will be played
Chris@127 497 // at the wrong rate because their rate differs from that of
Chris@127 498 // the main model.
Chris@127 499
Chris@150 500 if (modelRate == mainModelRate) {
Chris@150 501 if (modelRate != playbackRate) srNote = " " + tr("(R)");
Chris@127 502 } else {
Chris@150 503 // std::cerr << "Sample rate = " << modelRate << ", main model rate = " << mainModelRate << std::endl;
Chris@127 504 srNote = " " + tr("(X)");
Chris@127 505 }
Chris@127 506
Chris@127 507 QString desc = tr("%1 / %2Hz%3")
Chris@127 508 .arg(RealTime::frame2RealTime(waveformModel->getEndFrame(),
Chris@127 509 sampleRate)
Chris@127 510 .toText(false).c_str())
Chris@150 511 .arg(modelRate)
Chris@127 512 .arg(srNote);
Chris@127 513
Chris@127 514 if (r.x() < verticalScaleWidth + 5 + paint.fontMetrics().width(desc)) {
Chris@127 515 drawVisibleText(paint, verticalScaleWidth + 5,
Chris@127 516 height() - fontHeight + fontAscent - 6,
Chris@127 517 desc, OutlinedText);
Chris@127 518 }
Chris@127 519 }
Chris@127 520
Chris@127 521 if (m_manager &&
Chris@127 522 m_manager->getOverlayMode() == ViewManager::AllOverlays &&
Chris@127 523 r.y() + r.height() >= height() - m_layers.size() * fontHeight - 6) {
Chris@127 524
Chris@127 525 std::vector<QString> texts;
Chris@127 526 int maxTextWidth = 0;
Chris@127 527
Chris@127 528 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 529
Chris@127 530 QString text = (*i)->getLayerPresentationName();
Chris@127 531 int tw = paint.fontMetrics().width(text);
Chris@127 532 bool reduced = false;
Chris@127 533 while (tw > width() / 3 && text.length() > 4) {
Chris@127 534 if (!reduced && text.length() > 8) {
Chris@127 535 text = text.left(text.length() - 4);
Chris@127 536 } else {
Chris@127 537 text = text.left(text.length() - 2);
Chris@127 538 }
Chris@127 539 reduced = true;
Chris@127 540 tw = paint.fontMetrics().width(text + "...");
Chris@127 541 }
Chris@127 542 if (reduced) {
Chris@127 543 texts.push_back(text + "...");
Chris@127 544 } else {
Chris@127 545 texts.push_back(text);
Chris@127 546 }
Chris@127 547 if (tw > maxTextWidth) maxTextWidth = tw;
Chris@127 548 }
Chris@127 549
Chris@127 550 int lly = height() - 6;
Chris@133 551 int llx = width() - maxTextWidth - 5;
Chris@127 552
Chris@133 553 if (m_manager->getZoomWheelsEnabled()) {
Chris@133 554 lly -= 20;
Chris@133 555 llx -= 20;
Chris@133 556 }
Chris@133 557
Chris@133 558 if (r.x() + r.width() >= llx) {
Chris@127 559
Chris@127 560 for (int i = 0; i < texts.size(); ++i) {
Chris@127 561
Chris@127 562 if (i == texts.size() - 1) {
Chris@127 563 paint.setPen(Qt::black);
Chris@127 564 }
Chris@127 565
Chris@133 566 drawVisibleText(paint, llx,
Chris@127 567 lly - fontHeight + fontAscent,
Chris@127 568 texts[i], OutlinedText);
Chris@127 569
Chris@127 570 lly -= fontHeight;
Chris@127 571 }
Chris@127 572 }
Chris@127 573 }
Chris@127 574
Chris@127 575 if (m_clickedInRange && m_shiftPressed) {
Chris@127 576 if (m_manager && (m_manager->getToolMode() == ViewManager::NavigateMode)) {
Chris@127 577 //!!! be nice if this looked a bit more in keeping with the
Chris@127 578 //selection block
Chris@127 579 paint.setPen(Qt::blue);
Chris@127 580 paint.drawRect(m_clickPos.x(), m_clickPos.y(),
Chris@127 581 m_mousePos.x() - m_clickPos.x(),
Chris@127 582 m_mousePos.y() - m_clickPos.y());
Chris@127 583 }
Chris@127 584 }
Chris@127 585
Chris@127 586 if (selectionIsBeingEdited()) {
Chris@127 587
Chris@127 588 int offset = m_mousePos.x() - m_clickPos.x();
Chris@127 589 int p0 = getXForFrame(m_editingSelection.getStartFrame()) + offset;
Chris@127 590 int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset;
Chris@127 591
Chris@127 592 if (m_editingSelectionEdge < 0) {
Chris@127 593 p1 = getXForFrame(m_editingSelection.getEndFrame());
Chris@127 594 } else if (m_editingSelectionEdge > 0) {
Chris@127 595 p0 = getXForFrame(m_editingSelection.getStartFrame());
Chris@127 596 }
Chris@127 597
Chris@127 598 paint.save();
Chris@127 599 if (hasLightBackground()) {
Chris@127 600 paint.setPen(QPen(Qt::black, 2));
Chris@127 601 } else {
Chris@127 602 paint.setPen(QPen(Qt::white, 2));
Chris@127 603 }
Chris@127 604
Chris@127 605 //!!! duplicating display policy with View::drawSelections
Chris@127 606
Chris@127 607 if (m_editingSelectionEdge < 0) {
Chris@127 608 paint.drawLine(p0, 1, p1, 1);
Chris@127 609 paint.drawLine(p0, 0, p0, height());
Chris@127 610 paint.drawLine(p0, height() - 1, p1, height() - 1);
Chris@127 611 } else if (m_editingSelectionEdge > 0) {
Chris@127 612 paint.drawLine(p0, 1, p1, 1);
Chris@127 613 paint.drawLine(p1, 0, p1, height());
Chris@127 614 paint.drawLine(p0, height() - 1, p1, height() - 1);
Chris@127 615 } else {
Chris@127 616 paint.setBrush(Qt::NoBrush);
Chris@127 617 paint.drawRect(p0, 1, p1 - p0, height() - 2);
Chris@127 618 }
Chris@127 619 paint.restore();
Chris@127 620 }
Chris@127 621
Chris@127 622 paint.end();
Chris@127 623 }
Chris@127 624
Chris@127 625 Selection
Chris@127 626 Pane::getSelectionAt(int x, bool &closeToLeftEdge, bool &closeToRightEdge) const
Chris@127 627 {
Chris@127 628 closeToLeftEdge = closeToRightEdge = false;
Chris@127 629
Chris@127 630 if (!m_manager) return Selection();
Chris@127 631
Chris@127 632 long testFrame = getFrameForX(x - 5);
Chris@127 633 if (testFrame < 0) {
Chris@127 634 testFrame = getFrameForX(x);
Chris@127 635 if (testFrame < 0) return Selection();
Chris@127 636 }
Chris@127 637
Chris@127 638 Selection selection = m_manager->getContainingSelection(testFrame, true);
Chris@127 639 if (selection.isEmpty()) return selection;
Chris@127 640
Chris@127 641 int lx = getXForFrame(selection.getStartFrame());
Chris@127 642 int rx = getXForFrame(selection.getEndFrame());
Chris@127 643
Chris@127 644 int fuzz = 2;
Chris@127 645 if (x < lx - fuzz || x > rx + fuzz) return Selection();
Chris@127 646
Chris@127 647 int width = rx - lx;
Chris@127 648 fuzz = 3;
Chris@127 649 if (width < 12) fuzz = width / 4;
Chris@127 650 if (fuzz < 1) fuzz = 1;
Chris@127 651
Chris@127 652 if (x < lx + fuzz) closeToLeftEdge = true;
Chris@127 653 if (x > rx - fuzz) closeToRightEdge = true;
Chris@127 654
Chris@127 655 return selection;
Chris@127 656 }
Chris@127 657
Chris@127 658 void
Chris@127 659 Pane::mousePressEvent(QMouseEvent *e)
Chris@127 660 {
Chris@127 661 if (e->buttons() & Qt::RightButton) {
Chris@127 662 emit rightButtonMenuRequested(mapToGlobal(e->pos()));
Chris@127 663 return;
Chris@127 664 }
Chris@127 665
Chris@127 666 m_clickPos = e->pos();
Chris@127 667 m_clickedInRange = true;
Chris@127 668 m_editingSelection = Selection();
Chris@127 669 m_editingSelectionEdge = 0;
Chris@127 670 m_shiftPressed = (e->modifiers() & Qt::ShiftModifier);
Chris@127 671 m_ctrlPressed = (e->modifiers() & Qt::ControlModifier);
Chris@150 672 m_dragMode = UnresolvedDrag;
Chris@127 673
Chris@127 674 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@127 675 if (m_manager) mode = m_manager->getToolMode();
Chris@127 676
Chris@127 677 m_navigating = false;
Chris@127 678
Chris@127 679 if (mode == ViewManager::NavigateMode || (e->buttons() & Qt::MidButton)) {
Chris@127 680
Chris@127 681 if (mode != ViewManager::NavigateMode) {
Chris@127 682 setCursor(Qt::PointingHandCursor);
Chris@127 683 }
Chris@127 684
Chris@127 685 m_navigating = true;
Chris@127 686 m_dragCentreFrame = m_centreFrame;
Chris@127 687
Chris@136 688 //!!! pull out into function to go with mouse move code
Chris@136 689
Chris@136 690 m_dragStartMinValue = 0;
Chris@136 691
Chris@136 692 Layer *layer = 0;
Chris@136 693 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1);
Chris@136 694
Chris@136 695 if (layer) {
Chris@136 696 float min = 0.f, max = 0.f;
Chris@136 697 if (layer->getDisplayExtents(min, max)) {
Chris@136 698 m_dragStartMinValue = min;
Chris@136 699 }
Chris@136 700 }
Chris@136 701
Chris@127 702 } else if (mode == ViewManager::SelectMode) {
Chris@127 703
Chris@127 704 bool closeToLeft = false, closeToRight = false;
Chris@127 705 Selection selection = getSelectionAt(e->x(), closeToLeft, closeToRight);
Chris@127 706
Chris@127 707 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) {
Chris@127 708
Chris@127 709 m_manager->removeSelection(selection);
Chris@127 710
Chris@127 711 if (closeToLeft) {
Chris@127 712 m_selectionStartFrame = selection.getEndFrame();
Chris@127 713 } else {
Chris@127 714 m_selectionStartFrame = selection.getStartFrame();
Chris@127 715 }
Chris@127 716
Chris@127 717 m_manager->setInProgressSelection(selection, false);
Chris@127 718 m_resizing = true;
Chris@127 719
Chris@127 720 } else {
Chris@127 721
Chris@127 722 int mouseFrame = getFrameForX(e->x());
Chris@127 723 size_t resolution = 1;
Chris@127 724 int snapFrame = mouseFrame;
Chris@127 725
Chris@127 726 Layer *layer = getSelectedLayer();
Chris@127 727 if (layer && !m_shiftPressed) {
Chris@127 728 layer->snapToFeatureFrame(this, snapFrame,
Chris@127 729 resolution, Layer::SnapLeft);
Chris@127 730 }
Chris@127 731
Chris@127 732 if (snapFrame < 0) snapFrame = 0;
Chris@127 733 m_selectionStartFrame = snapFrame;
Chris@127 734 if (m_manager) {
Chris@127 735 m_manager->setInProgressSelection(Selection(snapFrame,
Chris@127 736 snapFrame + resolution),
Chris@127 737 !m_ctrlPressed);
Chris@127 738 }
Chris@127 739
Chris@127 740 m_resizing = false;
Chris@127 741 }
Chris@127 742
Chris@127 743 update();
Chris@127 744
Chris@127 745 } else if (mode == ViewManager::DrawMode) {
Chris@127 746
Chris@127 747 Layer *layer = getSelectedLayer();
Chris@127 748 if (layer && layer->isLayerEditable()) {
Chris@127 749 layer->drawStart(this, e);
Chris@127 750 }
Chris@127 751
Chris@127 752 } else if (mode == ViewManager::EditMode) {
Chris@127 753
Chris@127 754 if (!editSelectionStart(e)) {
Chris@127 755 Layer *layer = getSelectedLayer();
Chris@127 756 if (layer && layer->isLayerEditable()) {
Chris@127 757 layer->editStart(this, e);
Chris@127 758 }
Chris@127 759 }
Chris@127 760 }
Chris@127 761
Chris@127 762 emit paneInteractedWith();
Chris@127 763 }
Chris@127 764
Chris@127 765 void
Chris@127 766 Pane::mouseReleaseEvent(QMouseEvent *e)
Chris@127 767 {
Chris@127 768 if (e->buttons() & Qt::RightButton) {
Chris@127 769 return;
Chris@127 770 }
Chris@127 771
Chris@127 772 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@127 773 if (m_manager) mode = m_manager->getToolMode();
Chris@127 774
Chris@127 775 if (m_clickedInRange) {
Chris@127 776 mouseMoveEvent(e);
Chris@127 777 }
Chris@127 778
Chris@127 779 if (m_navigating || mode == ViewManager::NavigateMode) {
Chris@127 780
Chris@127 781 m_navigating = false;
Chris@127 782
Chris@127 783 if (mode != ViewManager::NavigateMode) {
Chris@127 784 // restore cursor
Chris@127 785 toolModeChanged();
Chris@127 786 }
Chris@127 787
Chris@127 788 if (m_shiftPressed) {
Chris@127 789
Chris@127 790 int x0 = std::min(m_clickPos.x(), m_mousePos.x());
Chris@127 791 int x1 = std::max(m_clickPos.x(), m_mousePos.x());
Chris@127 792 int w = x1 - x0;
Chris@127 793
Chris@127 794 int y0 = std::min(m_clickPos.y(), m_mousePos.y());
Chris@127 795 int y1 = std::max(m_clickPos.y(), m_mousePos.y());
Chris@127 796 // int h = y1 - y0;
Chris@127 797
Chris@127 798 long newStartFrame = getFrameForX(x0);
Chris@127 799
Chris@127 800 long visibleFrames = getEndFrame() - getStartFrame();
Chris@127 801 if (newStartFrame <= -visibleFrames) {
Chris@127 802 newStartFrame = -visibleFrames + 1;
Chris@127 803 }
Chris@127 804
Chris@127 805 if (newStartFrame >= long(getModelsEndFrame())) {
Chris@127 806 newStartFrame = getModelsEndFrame() - 1;
Chris@127 807 }
Chris@127 808
Chris@127 809 float ratio = float(w) / float(width());
Chris@127 810 // std::cerr << "ratio: " << ratio << std::endl;
Chris@127 811 size_t newZoomLevel = (size_t)nearbyint(m_zoomLevel * ratio);
Chris@127 812 if (newZoomLevel < 1) newZoomLevel = 1;
Chris@127 813
Chris@127 814 // std::cerr << "start: " << m_startFrame << ", level " << m_zoomLevel << std::endl;
Chris@127 815 setZoomLevel(getZoomConstraintBlockSize(newZoomLevel));
Chris@127 816 setStartFrame(newStartFrame);
Chris@127 817
Chris@127 818 //!!! lots of faff, shouldn't be here
Chris@127 819
Chris@127 820 QString unit;
Chris@127 821 float min, max;
Chris@127 822 bool log;
Chris@127 823 Layer *layer = 0;
Chris@127 824 for (LayerList::const_iterator i = m_layers.begin();
Chris@127 825 i != m_layers.end(); ++i) {
Chris@127 826 if ((*i)->getValueExtents(min, max, log, unit) &&
Chris@127 827 (*i)->getDisplayExtents(min, max)) {
Chris@127 828 layer = *i;
Chris@127 829 break;
Chris@127 830 }
Chris@127 831 }
Chris@127 832
Chris@127 833 if (layer) {
Chris@127 834 if (log) {
Chris@127 835 min = (min < 0.0) ? -log10f(-min) : (min == 0.0) ? 0.0 : log10f(min);
Chris@127 836 max = (max < 0.0) ? -log10f(-max) : (max == 0.0) ? 0.0 : log10f(max);
Chris@127 837 }
Chris@127 838 float rmin = min + ((max - min) * (height() - y1)) / height();
Chris@127 839 float rmax = min + ((max - min) * (height() - y0)) / height();
Chris@127 840 std::cerr << "min: " << min << ", max: " << max << ", y0: " << y0 << ", y1: " << y1 << ", h: " << height() << ", rmin: " << rmin << ", rmax: " << rmax << std::endl;
Chris@127 841 if (log) {
Chris@127 842 rmin = powf(10, rmin);
Chris@127 843 rmax = powf(10, rmax);
Chris@127 844 }
Chris@127 845 std::cerr << "finally: rmin: " << rmin << ", rmax: " << rmax << " " << unit.toStdString() << std::endl;
Chris@127 846
Chris@127 847 layer->setDisplayExtents(rmin, rmax);
Chris@127 848 }
Chris@127 849
Chris@127 850 //cerr << "mouseReleaseEvent: start frame now " << m_startFrame << endl;
Chris@127 851 // update();
Chris@127 852 }
Chris@127 853
Chris@127 854 } else if (mode == ViewManager::SelectMode) {
Chris@127 855
Chris@127 856 if (m_manager && m_manager->haveInProgressSelection()) {
Chris@127 857
Chris@127 858 bool exclusive;
Chris@127 859 Selection selection = m_manager->getInProgressSelection(exclusive);
Chris@127 860
Chris@127 861 if (selection.getEndFrame() < selection.getStartFrame() + 2) {
Chris@127 862 selection = Selection();
Chris@127 863 }
Chris@127 864
Chris@127 865 m_manager->clearInProgressSelection();
Chris@127 866
Chris@127 867 if (exclusive) {
Chris@127 868 m_manager->setSelection(selection);
Chris@127 869 } else {
Chris@127 870 m_manager->addSelection(selection);
Chris@127 871 }
Chris@127 872 }
Chris@127 873
Chris@127 874 update();
Chris@127 875
Chris@127 876 } else if (mode == ViewManager::DrawMode) {
Chris@127 877
Chris@127 878 Layer *layer = getSelectedLayer();
Chris@127 879 if (layer && layer->isLayerEditable()) {
Chris@127 880 layer->drawEnd(this, e);
Chris@127 881 update();
Chris@127 882 }
Chris@127 883
Chris@127 884 } else if (mode == ViewManager::EditMode) {
Chris@127 885
Chris@127 886 if (!editSelectionEnd(e)) {
Chris@127 887 Layer *layer = getSelectedLayer();
Chris@127 888 if (layer && layer->isLayerEditable()) {
Chris@127 889 layer->editEnd(this, e);
Chris@127 890 update();
Chris@127 891 }
Chris@127 892 }
Chris@127 893 }
Chris@127 894
Chris@127 895 m_clickedInRange = false;
Chris@127 896
Chris@127 897 emit paneInteractedWith();
Chris@127 898 }
Chris@127 899
Chris@127 900 void
Chris@127 901 Pane::mouseMoveEvent(QMouseEvent *e)
Chris@127 902 {
Chris@127 903 if (e->buttons() & Qt::RightButton) {
Chris@127 904 return;
Chris@127 905 }
Chris@127 906
Chris@127 907 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@127 908 if (m_manager) mode = m_manager->getToolMode();
Chris@127 909
Chris@127 910 QPoint prevPoint = m_identifyPoint;
Chris@127 911 m_identifyPoint = e->pos();
Chris@127 912
Chris@127 913 if (!m_clickedInRange) {
Chris@127 914
Chris@127 915 if (mode == ViewManager::SelectMode) {
Chris@127 916 bool closeToLeft = false, closeToRight = false;
Chris@127 917 getSelectionAt(e->x(), closeToLeft, closeToRight);
Chris@127 918 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) {
Chris@127 919 setCursor(Qt::SizeHorCursor);
Chris@127 920 } else {
Chris@127 921 setCursor(Qt::ArrowCursor);
Chris@127 922 }
Chris@127 923 }
Chris@127 924
Chris@127 925 //!!! if (mode != ViewManager::DrawMode) {
Chris@127 926
Chris@127 927 if (!m_manager->isPlaying()) {
Chris@127 928
Chris@127 929 if (getSelectedLayer()) {
Chris@127 930
Chris@127 931 bool previouslyIdentifying = m_identifyFeatures;
Chris@127 932 m_identifyFeatures = true;
Chris@127 933
Chris@127 934 if (m_identifyFeatures != previouslyIdentifying ||
Chris@127 935 m_identifyPoint != prevPoint) {
Chris@127 936 update();
Chris@127 937 }
Chris@127 938 }
Chris@127 939
Chris@127 940 }
Chris@127 941
Chris@127 942 // }
Chris@127 943
Chris@127 944 return;
Chris@127 945 }
Chris@127 946
Chris@127 947 if (m_navigating || mode == ViewManager::NavigateMode) {
Chris@127 948
Chris@127 949 if (m_shiftPressed) {
Chris@127 950
Chris@127 951 m_mousePos = e->pos();
Chris@127 952 update();
Chris@127 953
Chris@127 954 } else {
Chris@127 955
Chris@145 956 //!!! want to do some cleverness to avoid dragging left/right
Chris@145 957 // at the same time as up/down when the user moves the mouse
Chris@145 958 // diagonally.
Chris@145 959 // e.g. have horizontal and vertical thresholds and a series
Chris@145 960 // of states: unknown, constrained, free
Chris@145 961 //
Chris@145 962 // -> when the mouse first moves we're in unknown state:
Chris@145 963 // what then? the thing we really want to avoid is moving
Chris@145 964 // a tiny amount in the wrong direction, because usually
Chris@145 965 // the problem is that to move at all is expensive -- so what
Chris@145 966 // do we do?
Chris@145 967 //
Chris@145 968 // -> when it's moved more than say 10px in h or v
Chris@145 969 // direction we lock into h or v constrained mode. If it
Chris@145 970 // moves more than say 20px in the other direction
Chris@145 971 // subsequently, then we switch into free mode.
Chris@145 972
Chris@150 973 int xdiff = e->x() - m_clickPos.x();
Chris@150 974 int ydiff = e->y() - m_clickPos.y();
Chris@150 975 int smallThreshold = 10, bigThreshold = 50;
Chris@136 976
Chris@150 977 bool canMoveVertical = true;
Chris@150 978 bool canMoveHorizontal = true;
Chris@136 979
Chris@150 980 //!!! need to test whether the layer is actually draggable
Chris@150 981 // vertically before we do any of this
Chris@136 982
Chris@150 983 if (m_dragMode == UnresolvedDrag) {
Chris@136 984
Chris@150 985 if (abs(ydiff) > smallThreshold &&
Chris@150 986 abs(ydiff) > abs(xdiff) * 2) {
Chris@150 987 m_dragMode = VerticalDrag;
Chris@150 988 } else if (abs(xdiff) > smallThreshold &&
Chris@150 989 abs(xdiff) > abs(ydiff) * 2) {
Chris@150 990 m_dragMode = HorizontalDrag;
Chris@150 991 } else if (abs(xdiff) > smallThreshold &&
Chris@150 992 abs(ydiff) > smallThreshold) {
Chris@150 993 m_dragMode = FreeDrag;
Chris@150 994 } else {
Chris@150 995 // When playing, we don't want to disturb the play
Chris@150 996 // position too easily; when not playing, we don't
Chris@150 997 // want to move up/down too easily
Chris@150 998 if (m_manager && m_manager->isPlaying()) {
Chris@150 999 canMoveHorizontal = false;
Chris@150 1000 } else {
Chris@150 1001 canMoveVertical = false;
Chris@136 1002 }
Chris@136 1003 }
Chris@136 1004 }
Chris@150 1005
Chris@150 1006 if (m_dragMode == VerticalDrag) {
Chris@150 1007 if (abs(xdiff) > bigThreshold) m_dragMode = FreeDrag;
Chris@150 1008 else canMoveHorizontal = false;
Chris@150 1009 }
Chris@150 1010
Chris@150 1011 if (m_dragMode == HorizontalDrag) {
Chris@150 1012 if (abs(ydiff) > bigThreshold) m_dragMode = FreeDrag;
Chris@150 1013 else canMoveVertical = false;
Chris@150 1014 }
Chris@150 1015
Chris@150 1016 if (canMoveHorizontal) {
Chris@150 1017
Chris@150 1018 long frameOff = getFrameForX(e->x()) - getFrameForX(m_clickPos.x());
Chris@150 1019
Chris@150 1020 size_t newCentreFrame = m_dragCentreFrame;
Chris@150 1021
Chris@150 1022 if (frameOff < 0) {
Chris@150 1023 newCentreFrame -= frameOff;
Chris@150 1024 } else if (newCentreFrame >= size_t(frameOff)) {
Chris@150 1025 newCentreFrame -= frameOff;
Chris@150 1026 } else {
Chris@150 1027 newCentreFrame = 0;
Chris@150 1028 }
Chris@150 1029
Chris@150 1030 if (newCentreFrame >= getModelsEndFrame()) {
Chris@150 1031 newCentreFrame = getModelsEndFrame();
Chris@150 1032 if (newCentreFrame > 0) --newCentreFrame;
Chris@150 1033 }
Chris@150 1034
Chris@150 1035 if (getXForFrame(m_centreFrame) != getXForFrame(newCentreFrame)) {
Chris@150 1036 setCentreFrame(newCentreFrame);
Chris@150 1037 }
Chris@150 1038 }
Chris@150 1039
Chris@150 1040 //!!! For drag up/down, we need to: call getValueExtents
Chris@150 1041 //and getDisplayExtents and see whether both return true
Chris@150 1042 //(we can only drag up/down if they do); and check whether
Chris@150 1043 //the ranges returned differ (likewise). Then, we know
Chris@150 1044 //the height of the layer, so...
Chris@150 1045
Chris@150 1046 //!!! this should have its own function
Chris@150 1047
Chris@150 1048 if (canMoveVertical) {
Chris@150 1049
Chris@150 1050 Layer *layer = 0;
Chris@150 1051 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1);
Chris@150 1052
Chris@150 1053 if (layer) {
Chris@150 1054
Chris@150 1055 float vmin = 0.f, vmax = 0.f;
Chris@150 1056 bool vlog = false;
Chris@150 1057 QString vunit;
Chris@150 1058
Chris@150 1059 float dmin = 0.f, dmax = 0.f;
Chris@150 1060
Chris@150 1061 if (layer->getValueExtents(vmin, vmax, vlog, vunit) &&
Chris@150 1062 layer->getDisplayExtents(dmin, dmax) &&
Chris@150 1063 (dmin > vmin || dmax < vmax)) {
Chris@150 1064
Chris@150 1065 std::cerr << "ydiff = " << ydiff << std::endl;
Chris@150 1066
Chris@150 1067 float perpix = (dmax - dmin) / height();
Chris@150 1068 float valdiff = ydiff * perpix;
Chris@150 1069 std::cerr << "valdiff = " << valdiff << std::endl;
Chris@150 1070
Chris@150 1071 float newmin = m_dragStartMinValue + valdiff;
Chris@150 1072 float newmax = m_dragStartMinValue + (dmax - dmin) + valdiff;
Chris@150 1073 if (newmin < vmin) {
Chris@150 1074 newmax += vmin - newmin;
Chris@150 1075 newmin += vmin - newmin;
Chris@150 1076 }
Chris@150 1077 if (newmax > vmax) {
Chris@150 1078 newmin -= newmax - vmax;
Chris@150 1079 newmax -= newmax - vmax;
Chris@150 1080 }
Chris@150 1081 std::cerr << "(" << dmin << ", " << dmax << ") -> ("
Chris@150 1082 << newmin << ", " << newmax << ") (drag start " << m_dragStartMinValue << ")" << std::endl;
Chris@150 1083 layer->setDisplayExtents(newmin, newmax);
Chris@150 1084 }
Chris@150 1085 }
Chris@150 1086 }
Chris@150 1087 }
Chris@127 1088
Chris@127 1089 } else if (mode == ViewManager::SelectMode) {
Chris@127 1090
Chris@127 1091 int mouseFrame = getFrameForX(e->x());
Chris@127 1092 size_t resolution = 1;
Chris@127 1093 int snapFrameLeft = mouseFrame;
Chris@127 1094 int snapFrameRight = mouseFrame;
Chris@127 1095
Chris@127 1096 Layer *layer = getSelectedLayer();
Chris@127 1097 if (layer && !m_shiftPressed) {
Chris@127 1098 layer->snapToFeatureFrame(this, snapFrameLeft,
Chris@127 1099 resolution, Layer::SnapLeft);
Chris@127 1100 layer->snapToFeatureFrame(this, snapFrameRight,
Chris@127 1101 resolution, Layer::SnapRight);
Chris@127 1102 }
Chris@127 1103
Chris@127 1104 // std::cerr << "snap: frame = " << mouseFrame << ", start frame = " << m_selectionStartFrame << ", left = " << snapFrameLeft << ", right = " << snapFrameRight << std::endl;
Chris@127 1105
Chris@127 1106 if (snapFrameLeft < 0) snapFrameLeft = 0;
Chris@127 1107 if (snapFrameRight < 0) snapFrameRight = 0;
Chris@127 1108
Chris@127 1109 size_t min, max;
Chris@127 1110
Chris@127 1111 if (m_selectionStartFrame > snapFrameLeft) {
Chris@127 1112 min = snapFrameLeft;
Chris@127 1113 max = m_selectionStartFrame;
Chris@127 1114 } else if (snapFrameRight > m_selectionStartFrame) {
Chris@127 1115 min = m_selectionStartFrame;
Chris@127 1116 max = snapFrameRight;
Chris@127 1117 } else {
Chris@127 1118 min = snapFrameLeft;
Chris@127 1119 max = snapFrameRight;
Chris@127 1120 }
Chris@127 1121
Chris@127 1122 if (m_manager) {
Chris@127 1123 m_manager->setInProgressSelection(Selection(min, max),
Chris@127 1124 !m_resizing && !m_ctrlPressed);
Chris@127 1125 }
Chris@127 1126
Chris@127 1127 bool doScroll = false;
Chris@127 1128 if (!m_manager) doScroll = true;
Chris@127 1129 if (!m_manager->isPlaying()) doScroll = true;
Chris@127 1130 if (m_followPlay != PlaybackScrollContinuous) doScroll = true;
Chris@127 1131
Chris@127 1132 if (doScroll) {
Chris@127 1133 int offset = mouseFrame - getStartFrame();
Chris@127 1134 int available = getEndFrame() - getStartFrame();
Chris@127 1135 if (offset >= available * 0.95) {
Chris@127 1136 int move = int(offset - available * 0.95) + 1;
Chris@127 1137 setCentreFrame(m_centreFrame + move);
Chris@127 1138 } else if (offset <= available * 0.10) {
Chris@127 1139 int move = int(available * 0.10 - offset) + 1;
Chris@127 1140 if (m_centreFrame > move) {
Chris@127 1141 setCentreFrame(m_centreFrame - move);
Chris@127 1142 } else {
Chris@127 1143 setCentreFrame(0);
Chris@127 1144 }
Chris@127 1145 }
Chris@127 1146 }
Chris@127 1147
Chris@127 1148 update();
Chris@127 1149
Chris@127 1150 } else if (mode == ViewManager::DrawMode) {
Chris@127 1151
Chris@127 1152 Layer *layer = getSelectedLayer();
Chris@127 1153 if (layer && layer->isLayerEditable()) {
Chris@127 1154 layer->drawDrag(this, e);
Chris@127 1155 }
Chris@127 1156
Chris@127 1157 } else if (mode == ViewManager::EditMode) {
Chris@127 1158
Chris@127 1159 if (!editSelectionDrag(e)) {
Chris@127 1160 Layer *layer = getSelectedLayer();
Chris@127 1161 if (layer && layer->isLayerEditable()) {
Chris@127 1162 layer->editDrag(this, e);
Chris@127 1163 }
Chris@127 1164 }
Chris@127 1165 }
Chris@127 1166 }
Chris@127 1167
Chris@127 1168 void
Chris@127 1169 Pane::mouseDoubleClickEvent(QMouseEvent *e)
Chris@127 1170 {
Chris@127 1171 if (e->buttons() & Qt::RightButton) {
Chris@127 1172 return;
Chris@127 1173 }
Chris@127 1174
Chris@127 1175 // std::cerr << "mouseDoubleClickEvent" << std::endl;
Chris@127 1176
Chris@127 1177 m_clickPos = e->pos();
Chris@127 1178 m_clickedInRange = true;
Chris@127 1179 m_shiftPressed = (e->modifiers() & Qt::ShiftModifier);
Chris@127 1180 m_ctrlPressed = (e->modifiers() & Qt::ControlModifier);
Chris@127 1181
Chris@127 1182 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@127 1183 if (m_manager) mode = m_manager->getToolMode();
Chris@127 1184
Chris@127 1185 if (mode == ViewManager::NavigateMode ||
Chris@127 1186 mode == ViewManager::EditMode) {
Chris@127 1187
Chris@127 1188 Layer *layer = getSelectedLayer();
Chris@127 1189 if (layer && layer->isLayerEditable()) {
Chris@127 1190 layer->editOpen(this, e);
Chris@127 1191 }
Chris@127 1192 }
Chris@127 1193 }
Chris@127 1194
Chris@127 1195 void
Chris@127 1196 Pane::leaveEvent(QEvent *)
Chris@127 1197 {
Chris@127 1198 bool previouslyIdentifying = m_identifyFeatures;
Chris@127 1199 m_identifyFeatures = false;
Chris@127 1200 if (previouslyIdentifying) update();
Chris@127 1201 }
Chris@127 1202
Chris@127 1203 void
Chris@133 1204 Pane::resizeEvent(QResizeEvent *)
Chris@133 1205 {
Chris@133 1206 updateHeadsUpDisplay();
Chris@133 1207 }
Chris@133 1208
Chris@133 1209 void
Chris@127 1210 Pane::wheelEvent(QWheelEvent *e)
Chris@127 1211 {
Chris@127 1212 //std::cerr << "wheelEvent, delta " << e->delta() << std::endl;
Chris@127 1213
Chris@127 1214 int count = e->delta();
Chris@127 1215
Chris@127 1216 if (count > 0) {
Chris@127 1217 if (count >= 120) count /= 120;
Chris@127 1218 else count = 1;
Chris@127 1219 }
Chris@127 1220
Chris@127 1221 if (count < 0) {
Chris@127 1222 if (count <= -120) count /= 120;
Chris@127 1223 else count = -1;
Chris@127 1224 }
Chris@127 1225
Chris@127 1226 if (e->modifiers() & Qt::ControlModifier) {
Chris@127 1227
Chris@127 1228 // Scroll left or right, rapidly
Chris@127 1229
Chris@127 1230 if (getStartFrame() < 0 &&
Chris@127 1231 getEndFrame() >= getModelsEndFrame()) return;
Chris@127 1232
Chris@127 1233 long delta = ((width() / 2) * count * m_zoomLevel);
Chris@127 1234
Chris@127 1235 if (int(m_centreFrame) < delta) {
Chris@127 1236 setCentreFrame(0);
Chris@127 1237 } else if (int(m_centreFrame) - delta >= int(getModelsEndFrame())) {
Chris@127 1238 setCentreFrame(getModelsEndFrame());
Chris@127 1239 } else {
Chris@127 1240 setCentreFrame(m_centreFrame - delta);
Chris@127 1241 }
Chris@127 1242
Chris@127 1243 } else {
Chris@127 1244
Chris@127 1245 // Zoom in or out
Chris@127 1246
Chris@127 1247 int newZoomLevel = m_zoomLevel;
Chris@127 1248
Chris@127 1249 while (count > 0) {
Chris@127 1250 if (newZoomLevel <= 2) {
Chris@127 1251 newZoomLevel = 1;
Chris@127 1252 break;
Chris@127 1253 }
Chris@127 1254 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel - 1,
Chris@127 1255 ZoomConstraint::RoundDown);
Chris@127 1256 --count;
Chris@127 1257 }
Chris@127 1258
Chris@127 1259 while (count < 0) {
Chris@127 1260 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel + 1,
Chris@127 1261 ZoomConstraint::RoundUp);
Chris@127 1262 ++count;
Chris@127 1263 }
Chris@127 1264
Chris@127 1265 if (newZoomLevel != m_zoomLevel) {
Chris@127 1266 setZoomLevel(newZoomLevel);
Chris@127 1267 }
Chris@127 1268 }
Chris@127 1269
Chris@127 1270 emit paneInteractedWith();
Chris@127 1271 }
Chris@127 1272
Chris@132 1273 void
Chris@132 1274 Pane::horizontalThumbwheelMoved(int value)
Chris@132 1275 {
Chris@137 1276 //!!! dupe with updateHeadsUpDisplay
Chris@137 1277
Chris@132 1278 int count = 0;
Chris@132 1279 int level = 1;
Chris@137 1280
Chris@137 1281
Chris@137 1282 //!!! pull out into function (presumably in View)
Chris@137 1283 bool haveConstraint = false;
Chris@137 1284 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end();
Chris@137 1285 ++i) {
Chris@137 1286 if ((*i)->getZoomConstraint() && !(*i)->supportsOtherZoomLevels()) {
Chris@137 1287 haveConstraint = true;
Chris@137 1288 break;
Chris@137 1289 }
Chris@132 1290 }
Chris@132 1291
Chris@137 1292 if (haveConstraint) {
Chris@137 1293 while (true) {
Chris@137 1294 if (m_hthumb->getMaximumValue() - value == count) break;
Chris@137 1295 int newLevel = getZoomConstraintBlockSize(level + 1,
Chris@137 1296 ZoomConstraint::RoundUp);
Chris@137 1297 if (newLevel == level) break;
Chris@137 1298 level = newLevel;
Chris@137 1299 if (++count == 50) break;
Chris@137 1300 }
Chris@137 1301 } else {
Chris@137 1302 while (true) {
Chris@137 1303 if (m_hthumb->getMaximumValue() - value == count) break;
Chris@137 1304 int step = level / 10;
Chris@137 1305 int pwr = 0;
Chris@137 1306 while (step > 0) {
Chris@137 1307 ++pwr;
Chris@137 1308 step /= 2;
Chris@137 1309 }
Chris@137 1310 step = 1;
Chris@137 1311 while (pwr > 0) {
Chris@137 1312 step *= 2;
Chris@137 1313 --pwr;
Chris@137 1314 }
Chris@137 1315 // std::cerr << level << std::endl;
Chris@137 1316 level += step;
Chris@137 1317 if (++count == 100 || level > 262144) break;
Chris@137 1318 }
Chris@137 1319 }
Chris@137 1320
Chris@137 1321 std::cerr << "new level is " << level << std::endl;
Chris@132 1322 setZoomLevel(level);
Chris@132 1323 }
Chris@132 1324
Chris@132 1325 void
Chris@132 1326 Pane::verticalThumbwheelMoved(int value)
Chris@132 1327 {
Chris@133 1328 Layer *layer = 0;
Chris@133 1329 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1);
Chris@133 1330 if (layer) {
Chris@133 1331 int defaultStep = 0;
Chris@133 1332 int max = layer->getVerticalZoomSteps(defaultStep);
Chris@133 1333 if (max == 0) {
Chris@133 1334 updateHeadsUpDisplay();
Chris@133 1335 return;
Chris@133 1336 }
Chris@133 1337 if (value > max) {
Chris@133 1338 value = max;
Chris@133 1339 }
Chris@133 1340 layer->setVerticalZoomStep(value);
Chris@133 1341 }
Chris@132 1342 }
Chris@132 1343
Chris@127 1344 bool
Chris@127 1345 Pane::editSelectionStart(QMouseEvent *e)
Chris@127 1346 {
Chris@127 1347 if (!m_identifyFeatures ||
Chris@127 1348 !m_manager ||
Chris@127 1349 m_manager->getToolMode() != ViewManager::EditMode) {
Chris@127 1350 return false;
Chris@127 1351 }
Chris@127 1352
Chris@127 1353 bool closeToLeft, closeToRight;
Chris@127 1354 Selection s(getSelectionAt(e->x(), closeToLeft, closeToRight));
Chris@127 1355 if (s.isEmpty()) return false;
Chris@127 1356 m_editingSelection = s;
Chris@127 1357 m_editingSelectionEdge = (closeToLeft ? -1 : closeToRight ? 1 : 0);
Chris@127 1358 m_mousePos = e->pos();
Chris@127 1359 return true;
Chris@127 1360 }
Chris@127 1361
Chris@127 1362 bool
Chris@127 1363 Pane::editSelectionDrag(QMouseEvent *e)
Chris@127 1364 {
Chris@127 1365 if (m_editingSelection.isEmpty()) return false;
Chris@127 1366 m_mousePos = e->pos();
Chris@127 1367 update();
Chris@127 1368 return true;
Chris@127 1369 }
Chris@127 1370
Chris@127 1371 bool
Chris@127 1372 Pane::editSelectionEnd(QMouseEvent *e)
Chris@127 1373 {
Chris@127 1374 if (m_editingSelection.isEmpty()) return false;
Chris@127 1375
Chris@127 1376 int offset = m_mousePos.x() - m_clickPos.x();
Chris@127 1377 Layer *layer = getSelectedLayer();
Chris@127 1378
Chris@127 1379 if (offset == 0 || !layer) {
Chris@127 1380 m_editingSelection = Selection();
Chris@127 1381 return true;
Chris@127 1382 }
Chris@127 1383
Chris@127 1384 int p0 = getXForFrame(m_editingSelection.getStartFrame()) + offset;
Chris@127 1385 int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset;
Chris@127 1386
Chris@127 1387 long f0 = getFrameForX(p0);
Chris@127 1388 long f1 = getFrameForX(p1);
Chris@127 1389
Chris@127 1390 Selection newSelection(f0, f1);
Chris@127 1391
Chris@127 1392 if (m_editingSelectionEdge == 0) {
Chris@127 1393
Chris@127 1394 CommandHistory::getInstance()->startCompoundOperation
Chris@127 1395 (tr("Drag Selection"), true);
Chris@127 1396
Chris@127 1397 layer->moveSelection(m_editingSelection, f0);
Chris@127 1398
Chris@127 1399 } else {
Chris@127 1400
Chris@127 1401 CommandHistory::getInstance()->startCompoundOperation
Chris@127 1402 (tr("Resize Selection"), true);
Chris@127 1403
Chris@127 1404 if (m_editingSelectionEdge < 0) {
Chris@127 1405 f1 = m_editingSelection.getEndFrame();
Chris@127 1406 } else {
Chris@127 1407 f0 = m_editingSelection.getStartFrame();
Chris@127 1408 }
Chris@127 1409
Chris@127 1410 newSelection = Selection(f0, f1);
Chris@127 1411 layer->resizeSelection(m_editingSelection, newSelection);
Chris@127 1412 }
Chris@127 1413
Chris@127 1414 m_manager->removeSelection(m_editingSelection);
Chris@127 1415 m_manager->addSelection(newSelection);
Chris@127 1416
Chris@127 1417 CommandHistory::getInstance()->endCompoundOperation();
Chris@127 1418
Chris@127 1419 m_editingSelection = Selection();
Chris@127 1420 return true;
Chris@127 1421 }
Chris@127 1422
Chris@127 1423 void
Chris@127 1424 Pane::toolModeChanged()
Chris@127 1425 {
Chris@127 1426 ViewManager::ToolMode mode = m_manager->getToolMode();
Chris@127 1427 // std::cerr << "Pane::toolModeChanged(" << mode << ")" << std::endl;
Chris@127 1428
Chris@127 1429 switch (mode) {
Chris@127 1430
Chris@127 1431 case ViewManager::NavigateMode:
Chris@127 1432 setCursor(Qt::PointingHandCursor);
Chris@127 1433 break;
Chris@127 1434
Chris@127 1435 case ViewManager::SelectMode:
Chris@127 1436 setCursor(Qt::ArrowCursor);
Chris@127 1437 break;
Chris@127 1438
Chris@127 1439 case ViewManager::EditMode:
Chris@127 1440 setCursor(Qt::UpArrowCursor);
Chris@127 1441 break;
Chris@127 1442
Chris@127 1443 case ViewManager::DrawMode:
Chris@127 1444 setCursor(Qt::CrossCursor);
Chris@127 1445 break;
Chris@127 1446 /*
Chris@127 1447 case ViewManager::TextMode:
Chris@127 1448 setCursor(Qt::IBeamCursor);
Chris@127 1449 break;
Chris@127 1450 */
Chris@127 1451 }
Chris@127 1452 }
Chris@127 1453
Chris@133 1454 void
Chris@133 1455 Pane::zoomWheelsEnabledChanged()
Chris@133 1456 {
Chris@133 1457 updateHeadsUpDisplay();
Chris@133 1458 update();
Chris@133 1459 }
Chris@133 1460
Chris@133 1461 void
Chris@133 1462 Pane::zoomLevelChanged()
Chris@133 1463 {
Chris@133 1464 if (m_manager && m_manager->getZoomWheelsEnabled()) {
Chris@133 1465 updateHeadsUpDisplay();
Chris@133 1466 }
Chris@133 1467 }
Chris@133 1468
Chris@133 1469 void
Chris@133 1470 Pane::propertyContainerSelected(View *v, PropertyContainer *pc)
Chris@133 1471 {
Chris@133 1472 Layer *layer = 0;
Chris@133 1473
Chris@133 1474 if (getLayerCount() > 0) {
Chris@133 1475 layer = getLayer(getLayerCount() - 1);
Chris@133 1476 disconnect(layer, SIGNAL(verticalZoomChanged()),
Chris@133 1477 this, SLOT(verticalZoomChanged()));
Chris@133 1478 }
Chris@133 1479
Chris@133 1480 View::propertyContainerSelected(v, pc);
Chris@133 1481 updateHeadsUpDisplay();
Chris@133 1482
Chris@133 1483 if (getLayerCount() > 0) {
Chris@133 1484 layer = getLayer(getLayerCount() - 1);
Chris@133 1485 connect(layer, SIGNAL(verticalZoomChanged()),
Chris@133 1486 this, SLOT(verticalZoomChanged()));
Chris@133 1487 }
Chris@133 1488 }
Chris@133 1489
Chris@133 1490 void
Chris@133 1491 Pane::verticalZoomChanged()
Chris@133 1492 {
Chris@133 1493 Layer *layer = 0;
Chris@133 1494
Chris@133 1495 if (getLayerCount() > 0) {
Chris@133 1496
Chris@133 1497 layer = getLayer(getLayerCount() - 1);
Chris@133 1498
Chris@133 1499 if (m_vthumb && m_vthumb->isVisible()) {
Chris@133 1500 m_vthumb->setValue(layer->getCurrentVerticalZoomStep());
Chris@133 1501 }
Chris@133 1502 }
Chris@133 1503 }
Chris@133 1504
Chris@127 1505 QString
Chris@127 1506 Pane::toXmlString(QString indent, QString extraAttributes) const
Chris@127 1507 {
Chris@127 1508 return View::toXmlString
Chris@127 1509 (indent,
Chris@127 1510 QString("type=\"pane\" centreLineVisible=\"%1\" height=\"%2\" %3")
Chris@127 1511 .arg(m_centreLineVisible).arg(height()).arg(extraAttributes));
Chris@127 1512 }
Chris@127 1513
Chris@127 1514
Chris@127 1515 #ifdef INCLUDE_MOCFILES
Chris@127 1516 #include "Pane.moc.cpp"
Chris@127 1517 #endif
Chris@127 1518