annotate widgets/Pane.cpp @ 50:75cfbc6e709b

* more MainWindow/Document stuff
author Chris Cannam
date Wed, 08 Mar 2006 17:47:58 +0000
parents 2818ec5d1985
children d2eac322d71b
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 A waveform viewer and audio annotation editor.
Chris@5 5 Chris Cannam, Queen Mary University of London, 2005-2006
Chris@0 6
Chris@0 7 This is experimental software. Not for distribution.
Chris@0 8 */
Chris@0 9
Chris@0 10 #include "widgets/Pane.h"
Chris@0 11 #include "base/Layer.h"
Chris@0 12 #include "base/Model.h"
Chris@0 13 #include "base/ZoomConstraint.h"
Chris@0 14 #include "base/RealTime.h"
Chris@0 15 #include "base/Profiler.h"
Chris@13 16 #include "base/ViewManager.h"
Chris@41 17 #include "layer/WaveformLayer.h"
Chris@0 18
Chris@0 19 #include <QPaintEvent>
Chris@0 20 #include <QPainter>
Chris@0 21 #include <iostream>
Chris@0 22 #include <cmath>
Chris@0 23
Chris@0 24 using std::cerr;
Chris@0 25 using std::endl;
Chris@0 26
Chris@0 27 Pane::Pane(QWidget *w) :
Chris@0 28 View(w, true),
Chris@0 29 m_identifyFeatures(false),
Chris@0 30 m_clickedInRange(false),
Chris@0 31 m_shiftPressed(false),
Chris@13 32 m_ctrlPressed(false),
Chris@17 33 m_navigating(false),
Chris@17 34 m_resizing(false),
Chris@0 35 m_centreLineVisible(true)
Chris@0 36 {
Chris@0 37 setObjectName("Pane");
Chris@0 38 setMouseTracking(true);
Chris@0 39 }
Chris@0 40
Chris@0 41 bool
Chris@44 42 Pane::shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos) const
Chris@0 43 {
Chris@42 44 QPoint discard;
Chris@42 45 bool b0, b1;
Chris@42 46
Chris@42 47 if (layer == getSelectedLayer() &&
Chris@42 48 !shouldIlluminateLocalSelection(discard, b0, b1)) {
Chris@42 49
Chris@27 50 pos = m_identifyPoint;
Chris@27 51 return m_identifyFeatures;
Chris@27 52 }
Chris@0 53
Chris@0 54 return false;
Chris@0 55 }
Chris@0 56
Chris@42 57 bool
Chris@42 58 Pane::shouldIlluminateLocalSelection(QPoint &pos,
Chris@42 59 bool &closeToLeft,
Chris@44 60 bool &closeToRight) const
Chris@42 61 {
Chris@42 62 if (m_identifyFeatures &&
Chris@42 63 m_manager &&
Chris@42 64 m_manager->getToolMode() == ViewManager::EditMode &&
Chris@42 65 !m_manager->getSelections().empty() &&
Chris@42 66 !selectionIsBeingEdited()) {
Chris@42 67
Chris@42 68 Selection s(getSelectionAt(m_identifyPoint.x(),
Chris@42 69 closeToLeft, closeToRight));
Chris@42 70
Chris@42 71 if (!s.isEmpty()) {
Chris@42 72 if (getSelectedLayer() && getSelectedLayer()->isLayerEditable()) {
Chris@42 73
Chris@42 74 pos = m_identifyPoint;
Chris@42 75 return true;
Chris@42 76 }
Chris@42 77 }
Chris@42 78 }
Chris@42 79
Chris@42 80 return false;
Chris@42 81 }
Chris@42 82
Chris@42 83 bool
Chris@42 84 Pane::selectionIsBeingEdited() const
Chris@42 85 {
Chris@42 86 if (!m_editingSelection.isEmpty()) {
Chris@42 87 if (m_mousePos != m_clickPos &&
Chris@42 88 getFrameForX(m_mousePos.x()) != getFrameForX(m_clickPos.x())) {
Chris@42 89 return true;
Chris@42 90 }
Chris@42 91 }
Chris@42 92 return false;
Chris@42 93 }
Chris@42 94
Chris@0 95 void
Chris@0 96 Pane::setCentreLineVisible(bool visible)
Chris@0 97 {
Chris@0 98 m_centreLineVisible = visible;
Chris@0 99 update();
Chris@0 100 }
Chris@0 101
Chris@0 102 void
Chris@0 103 Pane::paintEvent(QPaintEvent *e)
Chris@0 104 {
Chris@0 105 QPainter paint;
Chris@0 106
Chris@0 107 QRect r(rect());
Chris@0 108
Chris@0 109 if (e) {
Chris@0 110 r = e->rect();
Chris@0 111 }
Chris@0 112 /*
Chris@0 113 paint.begin(this);
Chris@0 114 paint.setClipRect(r);
Chris@0 115
Chris@0 116 if (hasLightBackground()) {
Chris@0 117 paint.setPen(Qt::white);
Chris@0 118 paint.setBrush(Qt::white);
Chris@0 119 } else {
Chris@0 120 paint.setPen(Qt::black);
Chris@0 121 paint.setBrush(Qt::black);
Chris@0 122 }
Chris@0 123 paint.drawRect(r);
Chris@0 124
Chris@0 125 paint.end();
Chris@0 126 */
Chris@0 127 View::paintEvent(e);
Chris@0 128
Chris@0 129 paint.begin(this);
Chris@0 130
Chris@0 131 if (e) {
Chris@0 132 paint.setClipRect(r);
Chris@0 133 }
Chris@41 134
Chris@41 135 const Model *waveformModel = 0; // just for reporting purposes
Chris@41 136
Chris@0 137 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
Chris@0 138 --vi;
Chris@0 139
Chris@41 140 if (dynamic_cast<WaveformLayer *>(*vi)) {
Chris@41 141 waveformModel = (*vi)->getModel();
Chris@41 142 }
Chris@41 143
Chris@44 144 int sw = (*vi)->getVerticalScaleWidth(this, paint);
Chris@0 145
Chris@0 146 if (sw > 0 && r.left() < sw) {
Chris@0 147
Chris@0 148 // Profiler profiler("Pane::paintEvent - painting vertical scale", true);
Chris@0 149
Chris@0 150 // std::cerr << "Pane::paintEvent: calling paint.save() in vertical scale block" << std::endl;
Chris@0 151 paint.save();
Chris@0 152
Chris@0 153 paint.setPen(Qt::black);
Chris@0 154 paint.setBrush(Qt::white);
Chris@0 155 paint.drawRect(0, 0, sw, height());
Chris@0 156
Chris@0 157 paint.setBrush(Qt::NoBrush);
Chris@44 158 (*vi)->paintVerticalScale(this, paint, QRect(0, 0, sw, height()));
Chris@0 159
Chris@0 160 paint.restore();
Chris@0 161 }
Chris@41 162
Chris@0 163 if (m_identifyFeatures) {
Chris@25 164
Chris@25 165 QPoint pos = m_identifyPoint;
Chris@44 166 QString desc = (*vi)->getFeatureDescription(this, pos);
Chris@25 167
Chris@25 168 if (desc != "") {
Chris@25 169
Chris@25 170 paint.save();
Chris@25 171
Chris@25 172 int tabStop =
Chris@25 173 paint.fontMetrics().width(tr("Some lengthy prefix:"));
Chris@25 174
Chris@25 175 QRect boundingRect =
Chris@25 176 paint.fontMetrics().boundingRect
Chris@25 177 (rect(),
Chris@25 178 Qt::AlignRight | Qt::AlignTop | Qt::TextExpandTabs,
Chris@25 179 desc, tabStop);
Chris@25 180
Chris@25 181 if (hasLightBackground()) {
Chris@25 182 paint.setPen(Qt::NoPen);
Chris@25 183 paint.setBrush(QColor(250, 250, 250, 200));
Chris@25 184 } else {
Chris@25 185 paint.setPen(Qt::NoPen);
Chris@25 186 paint.setBrush(QColor(50, 50, 50, 200));
Chris@25 187 }
Chris@25 188
Chris@25 189 int extra = paint.fontMetrics().descent();
Chris@25 190 paint.drawRect(width() - boundingRect.width() - 10 - extra,
Chris@25 191 10 - extra,
Chris@25 192 boundingRect.width() + 2 * extra,
Chris@25 193 boundingRect.height() + extra);
Chris@25 194
Chris@25 195 if (hasLightBackground()) {
Chris@25 196 paint.setPen(QColor(150, 20, 0));
Chris@25 197 } else {
Chris@25 198 paint.setPen(QColor(255, 150, 100));
Chris@25 199 }
Chris@25 200
Chris@25 201 QTextOption option;
Chris@25 202 option.setWrapMode(QTextOption::NoWrap);
Chris@25 203 option.setAlignment(Qt::AlignRight | Qt::AlignTop);
Chris@25 204 option.setTabStop(tabStop);
Chris@25 205 paint.drawText(QRectF(width() - boundingRect.width() - 10, 10,
Chris@25 206 boundingRect.width(),
Chris@25 207 boundingRect.height()),
Chris@25 208 desc,
Chris@25 209 option);
Chris@25 210
Chris@25 211 paint.restore();
Chris@25 212 }
Chris@0 213 }
Chris@0 214
Chris@0 215 break;
Chris@0 216 }
Chris@0 217
Chris@0 218 if (m_centreLineVisible) {
Chris@0 219
Chris@0 220 if (hasLightBackground()) {
Chris@0 221 paint.setPen(QColor(50, 50, 50));
Chris@0 222 } else {
Chris@0 223 paint.setPen(QColor(200, 200, 200));
Chris@0 224 }
Chris@0 225 paint.setBrush(Qt::NoBrush);
Chris@0 226 paint.drawLine(width() / 2, 0, width() / 2, height() - 1);
Chris@0 227
Chris@0 228 // QFont font(paint.font());
Chris@0 229 // font.setBold(true);
Chris@0 230 // paint.setFont(font);
Chris@0 231
Chris@0 232 int sampleRate = getModelsSampleRate();
Chris@0 233 int y = height() - paint.fontMetrics().height()
Chris@0 234 + paint.fontMetrics().ascent() - 6;
Chris@0 235
Chris@0 236 LayerList::iterator vi = m_layers.end();
Chris@0 237
Chris@0 238 if (vi != m_layers.begin()) {
Chris@0 239
Chris@0 240 switch ((*--vi)->getPreferredFrameCountPosition()) {
Chris@0 241
Chris@0 242 case Layer::PositionTop:
Chris@0 243 y = paint.fontMetrics().ascent() + 6;
Chris@0 244 break;
Chris@0 245
Chris@0 246 case Layer::PositionMiddle:
Chris@0 247 y = (height() - paint.fontMetrics().height()) / 2
Chris@0 248 + paint.fontMetrics().ascent();
Chris@0 249 break;
Chris@0 250
Chris@0 251 case Layer::PositionBottom:
Chris@0 252 // y already set correctly
Chris@0 253 break;
Chris@0 254 }
Chris@0 255 }
Chris@0 256
Chris@0 257 if (sampleRate) {
Chris@0 258
Chris@0 259 QString text(QString::fromStdString
Chris@0 260 (RealTime::frame2RealTime
Chris@0 261 (m_centreFrame, sampleRate).toText(true)));
Chris@0 262
Chris@0 263 int tw = paint.fontMetrics().width(text);
Chris@0 264 int x = width()/2 - 4 - tw;
Chris@0 265
Chris@0 266 if (hasLightBackground()) {
Chris@0 267 paint.setPen(palette().background().color());
Chris@0 268 for (int dx = -1; dx <= 1; ++dx) {
Chris@0 269 for (int dy = -1; dy <= 1; ++dy) {
Chris@0 270 if ((dx && dy) || !(dx || dy)) continue;
Chris@0 271 paint.drawText(x + dx, y + dy, text);
Chris@0 272 }
Chris@0 273 }
Chris@0 274 paint.setPen(QColor(50, 50, 50));
Chris@0 275 } else {
Chris@0 276 paint.setPen(QColor(200, 200, 200));
Chris@0 277 }
Chris@0 278
Chris@0 279 paint.drawText(x, y, text);
Chris@0 280 }
Chris@0 281
Chris@0 282 QString text = QString("%1").arg(m_centreFrame);
Chris@0 283
Chris@0 284 int tw = paint.fontMetrics().width(text);
Chris@0 285 int x = width()/2 + 4;
Chris@0 286
Chris@0 287 if (hasLightBackground()) {
Chris@0 288 paint.setPen(palette().background().color());
Chris@0 289 for (int dx = -1; dx <= 1; ++dx) {
Chris@0 290 for (int dy = -1; dy <= 1; ++dy) {
Chris@0 291 if ((dx && dy) || !(dx || dy)) continue;
Chris@0 292 paint.drawText(x + dx, y + dy, text);
Chris@0 293 }
Chris@0 294 }
Chris@0 295 paint.setPen(QColor(50, 50, 50));
Chris@0 296 } else {
Chris@0 297 paint.setPen(QColor(200, 200, 200));
Chris@0 298 }
Chris@0 299 paint.drawText(x, y, text);
Chris@41 300
Chris@41 301 if (waveformModel) {
Chris@49 302
Chris@50 303 size_t mainModelRate = m_manager->getMainModelSampleRate();
Chris@50 304 size_t playbackRate = m_manager->getPlaybackSampleRate();
Chris@50 305
Chris@50 306 QString srNote = "";
Chris@50 307
Chris@49 308 // Show (R) for waveform models that will be resampled on
Chris@50 309 // playback, and (X) for waveform models that will be
Chris@50 310 // played at the wrong rate because their rate differs
Chris@50 311 // from that of the main model.
Chris@49 312
Chris@50 313 if (sampleRate == mainModelRate) {
Chris@50 314 if (sampleRate != playbackRate) srNote = " " + tr("(R)");
Chris@50 315 } else {
Chris@50 316 srNote = " " + tr("(X)");
Chris@50 317 }
Chris@50 318
Chris@48 319 QString desc = tr("%1 / %2Hz%3")
Chris@41 320 .arg(RealTime::frame2RealTime(waveformModel->getEndFrame(),
Chris@48 321 sampleRate)
Chris@41 322 .toText(false).c_str())
Chris@48 323 .arg(sampleRate)
Chris@50 324 .arg(srNote);
Chris@41 325
Chris@41 326 paint.drawText(width() - paint.fontMetrics().width(desc) - 5,
Chris@41 327 height() - paint.fontMetrics().height() +
Chris@41 328 paint.fontMetrics().ascent() - 6,
Chris@41 329 desc);
Chris@41 330 }
Chris@0 331 }
Chris@0 332
Chris@0 333 if (m_clickedInRange && m_shiftPressed) {
Chris@19 334 if (m_manager && (m_manager->getToolMode() == ViewManager::NavigateMode)) {
Chris@19 335 //!!! be nice if this looked a bit more in keeping with the
Chris@19 336 //selection block
Chris@19 337 paint.setPen(Qt::blue);
Chris@19 338 paint.drawRect(m_clickPos.x(), m_clickPos.y(),
Chris@19 339 m_mousePos.x() - m_clickPos.x(),
Chris@19 340 m_mousePos.y() - m_clickPos.y());
Chris@19 341 }
Chris@0 342 }
Chris@0 343
Chris@42 344 if (selectionIsBeingEdited()) {
Chris@42 345
Chris@42 346 int offset = m_mousePos.x() - m_clickPos.x();
Chris@42 347 int p0 = getXForFrame(m_editingSelection.getStartFrame()) + offset;
Chris@42 348 int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset;
Chris@42 349
Chris@42 350 if (m_editingSelectionEdge < 0) {
Chris@42 351 p1 = getXForFrame(m_editingSelection.getEndFrame());
Chris@42 352 } else if (m_editingSelectionEdge > 0) {
Chris@42 353 p0 = getXForFrame(m_editingSelection.getStartFrame());
Chris@42 354 }
Chris@42 355
Chris@42 356 paint.save();
Chris@42 357 if (hasLightBackground()) {
Chris@42 358 paint.setPen(QPen(Qt::black, 2));
Chris@42 359 } else {
Chris@42 360 paint.setPen(QPen(Qt::white, 2));
Chris@42 361 }
Chris@42 362
Chris@42 363 //!!! duplicating display policy with View::drawSelections
Chris@42 364
Chris@42 365 if (m_editingSelectionEdge < 0) {
Chris@42 366 paint.drawLine(p0, 1, p1, 1);
Chris@42 367 paint.drawLine(p0, 0, p0, height());
Chris@42 368 paint.drawLine(p0, height() - 1, p1, height() - 1);
Chris@42 369 } else if (m_editingSelectionEdge > 0) {
Chris@42 370 paint.drawLine(p0, 1, p1, 1);
Chris@42 371 paint.drawLine(p1, 0, p1, height());
Chris@42 372 paint.drawLine(p0, height() - 1, p1, height() - 1);
Chris@42 373 } else {
Chris@42 374 paint.setBrush(Qt::NoBrush);
Chris@42 375 paint.drawRect(p0, 1, p1 - p0, height() - 2);
Chris@42 376 }
Chris@42 377 paint.restore();
Chris@42 378 }
Chris@42 379
Chris@0 380 paint.end();
Chris@0 381 }
Chris@0 382
Chris@17 383 Selection
Chris@44 384 Pane::getSelectionAt(int x, bool &closeToLeftEdge, bool &closeToRightEdge) const
Chris@17 385 {
Chris@17 386 closeToLeftEdge = closeToRightEdge = false;
Chris@17 387
Chris@17 388 if (!m_manager) return Selection();
Chris@17 389
Chris@20 390 long testFrame = getFrameForX(x - 5);
Chris@17 391 if (testFrame < 0) {
Chris@20 392 testFrame = getFrameForX(x);
Chris@17 393 if (testFrame < 0) return Selection();
Chris@17 394 }
Chris@17 395
Chris@17 396 Selection selection = m_manager->getContainingSelection(testFrame, true);
Chris@17 397 if (selection.isEmpty()) return selection;
Chris@17 398
Chris@20 399 int lx = getXForFrame(selection.getStartFrame());
Chris@20 400 int rx = getXForFrame(selection.getEndFrame());
Chris@17 401
Chris@17 402 int fuzz = 2;
Chris@17 403 if (x < lx - fuzz || x > rx + fuzz) return Selection();
Chris@17 404
Chris@17 405 int width = rx - lx;
Chris@17 406 fuzz = 3;
Chris@17 407 if (width < 12) fuzz = width / 4;
Chris@17 408 if (fuzz < 1) fuzz = 1;
Chris@17 409
Chris@17 410 if (x < lx + fuzz) closeToLeftEdge = true;
Chris@17 411 if (x > rx - fuzz) closeToRightEdge = true;
Chris@17 412
Chris@17 413 return selection;
Chris@17 414 }
Chris@17 415
Chris@0 416 void
Chris@0 417 Pane::mousePressEvent(QMouseEvent *e)
Chris@0 418 {
Chris@0 419 m_clickPos = e->pos();
Chris@0 420 m_clickedInRange = true;
Chris@42 421 m_editingSelection = Selection();
Chris@42 422 m_editingSelectionEdge = 0;
Chris@0 423 m_shiftPressed = (e->modifiers() & Qt::ShiftModifier);
Chris@13 424 m_ctrlPressed = (e->modifiers() & Qt::ControlModifier);
Chris@13 425
Chris@13 426 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@13 427 if (m_manager) mode = m_manager->getToolMode();
Chris@13 428
Chris@17 429 m_navigating = false;
Chris@13 430
Chris@17 431 if (mode == ViewManager::NavigateMode || (e->buttons() & Qt::MidButton)) {
Chris@17 432
Chris@17 433 if (mode != ViewManager::NavigateMode) {
Chris@17 434 setCursor(Qt::PointingHandCursor);
Chris@17 435 }
Chris@17 436
Chris@17 437 m_navigating = true;
Chris@13 438 m_dragCentreFrame = m_centreFrame;
Chris@13 439
Chris@13 440 } else if (mode == ViewManager::SelectMode) {
Chris@13 441
Chris@17 442 bool closeToLeft = false, closeToRight = false;
Chris@17 443 Selection selection = getSelectionAt(e->x(), closeToLeft, closeToRight);
Chris@17 444
Chris@17 445 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) {
Chris@17 446
Chris@17 447 m_manager->removeSelection(selection);
Chris@17 448
Chris@17 449 if (closeToLeft) {
Chris@17 450 m_selectionStartFrame = selection.getEndFrame();
Chris@17 451 } else {
Chris@17 452 m_selectionStartFrame = selection.getStartFrame();
Chris@17 453 }
Chris@17 454
Chris@17 455 m_manager->setInProgressSelection(selection, false);
Chris@17 456 m_resizing = true;
Chris@13 457
Chris@17 458 } else {
Chris@17 459
Chris@20 460 int mouseFrame = getFrameForX(e->x());
Chris@17 461 size_t resolution = 1;
Chris@17 462 int snapFrame = mouseFrame;
Chris@17 463
Chris@17 464 Layer *layer = getSelectedLayer();
Chris@17 465 if (layer) {
Chris@44 466 layer->snapToFeatureFrame(this, snapFrame,
Chris@44 467 resolution, Layer::SnapLeft);
Chris@17 468 }
Chris@17 469
Chris@17 470 if (snapFrame < 0) snapFrame = 0;
Chris@17 471 m_selectionStartFrame = snapFrame;
Chris@17 472 if (m_manager) {
Chris@17 473 m_manager->setInProgressSelection(Selection(snapFrame,
Chris@17 474 snapFrame + resolution),
Chris@17 475 !m_ctrlPressed);
Chris@17 476 }
Chris@17 477
Chris@17 478 m_resizing = false;
Chris@17 479 }
Chris@17 480
Chris@17 481 update();
Chris@17 482
Chris@17 483 } else if (mode == ViewManager::DrawMode) {
Chris@17 484
Chris@13 485 Layer *layer = getSelectedLayer();
Chris@23 486 if (layer && layer->isLayerEditable()) {
Chris@44 487 layer->drawStart(this, e);
Chris@13 488 }
Chris@18 489
Chris@18 490 } else if (mode == ViewManager::EditMode) {
Chris@18 491
Chris@42 492 if (!editSelectionStart(e)) {
Chris@42 493 Layer *layer = getSelectedLayer();
Chris@42 494 if (layer && layer->isLayerEditable()) {
Chris@44 495 layer->editStart(this, e);
Chris@42 496 }
Chris@18 497 }
Chris@13 498 }
Chris@0 499
Chris@0 500 emit paneInteractedWith();
Chris@0 501 }
Chris@0 502
Chris@0 503 void
Chris@0 504 Pane::mouseReleaseEvent(QMouseEvent *e)
Chris@0 505 {
Chris@13 506 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@13 507 if (m_manager) mode = m_manager->getToolMode();
Chris@13 508
Chris@0 509 if (m_clickedInRange) {
Chris@0 510 mouseMoveEvent(e);
Chris@0 511 }
Chris@0 512
Chris@17 513 if (m_navigating || mode == ViewManager::NavigateMode) {
Chris@17 514
Chris@17 515 m_navigating = false;
Chris@17 516
Chris@17 517 if (mode != ViewManager::NavigateMode) {
Chris@17 518 // restore cursor
Chris@17 519 toolModeChanged();
Chris@17 520 }
Chris@0 521
Chris@13 522 if (m_shiftPressed) {
Chris@0 523
Chris@13 524 int x0 = std::min(m_clickPos.x(), m_mousePos.x());
Chris@13 525 int x1 = std::max(m_clickPos.x(), m_mousePos.x());
Chris@13 526 int w = x1 - x0;
Chris@13 527
Chris@20 528 long newStartFrame = getFrameForX(x0);
Chris@13 529
Chris@20 530 long visibleFrames = getEndFrame() - getStartFrame();
Chris@20 531 if (newStartFrame <= -visibleFrames) {
Chris@20 532 newStartFrame = -visibleFrames + 1;
Chris@13 533 }
Chris@13 534
Chris@13 535 if (newStartFrame >= long(getModelsEndFrame())) {
Chris@13 536 newStartFrame = getModelsEndFrame() - 1;
Chris@13 537 }
Chris@13 538
Chris@13 539 float ratio = float(w) / float(width());
Chris@13 540 // std::cerr << "ratio: " << ratio << std::endl;
Chris@13 541 size_t newZoomLevel = (size_t)nearbyint(m_zoomLevel * ratio);
Chris@13 542 if (newZoomLevel < 1) newZoomLevel = 1;
Chris@13 543
Chris@13 544 // std::cerr << "start: " << m_startFrame << ", level " << m_zoomLevel << std::endl;
Chris@13 545 setZoomLevel(getZoomConstraintBlockSize(newZoomLevel));
Chris@13 546 setStartFrame(newStartFrame);
Chris@13 547
Chris@13 548 //cerr << "mouseReleaseEvent: start frame now " << m_startFrame << endl;
Chris@13 549 // update();
Chris@0 550 }
Chris@0 551
Chris@13 552 } else if (mode == ViewManager::SelectMode) {
Chris@13 553
Chris@13 554 if (m_manager && m_manager->haveInProgressSelection()) {
Chris@13 555
Chris@13 556 bool exclusive;
Chris@13 557 Selection selection = m_manager->getInProgressSelection(exclusive);
Chris@13 558
Chris@13 559 if (selection.getEndFrame() < selection.getStartFrame() + 2) {
Chris@13 560 selection = Selection();
Chris@13 561 }
Chris@13 562
Chris@13 563 m_manager->clearInProgressSelection();
Chris@13 564
Chris@13 565 if (exclusive) {
Chris@13 566 m_manager->setSelection(selection);
Chris@13 567 } else {
Chris@13 568 m_manager->addSelection(selection);
Chris@13 569 }
Chris@0 570 }
Chris@13 571
Chris@13 572 update();
Chris@17 573
Chris@17 574 } else if (mode == ViewManager::DrawMode) {
Chris@17 575
Chris@17 576 Layer *layer = getSelectedLayer();
Chris@23 577 if (layer && layer->isLayerEditable()) {
Chris@44 578 layer->drawEnd(this, e);
Chris@17 579 update();
Chris@17 580 }
Chris@18 581
Chris@18 582 } else if (mode == ViewManager::EditMode) {
Chris@18 583
Chris@42 584 if (!editSelectionEnd(e)) {
Chris@42 585 Layer *layer = getSelectedLayer();
Chris@42 586 if (layer && layer->isLayerEditable()) {
Chris@44 587 layer->editEnd(this, e);
Chris@42 588 update();
Chris@42 589 }
Chris@18 590 }
Chris@17 591 }
Chris@0 592
Chris@0 593 m_clickedInRange = false;
Chris@0 594
Chris@0 595 emit paneInteractedWith();
Chris@0 596 }
Chris@0 597
Chris@0 598 void
Chris@0 599 Pane::mouseMoveEvent(QMouseEvent *e)
Chris@0 600 {
Chris@13 601 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@13 602 if (m_manager) mode = m_manager->getToolMode();
Chris@13 603
Chris@28 604 QPoint prevPoint = m_identifyPoint;
Chris@28 605 m_identifyPoint = e->pos();
Chris@28 606
Chris@0 607 if (!m_clickedInRange) {
Chris@0 608
Chris@17 609 if (mode == ViewManager::SelectMode) {
Chris@17 610 bool closeToLeft = false, closeToRight = false;
Chris@17 611 getSelectionAt(e->x(), closeToLeft, closeToRight);
Chris@17 612 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) {
Chris@17 613 setCursor(Qt::SizeHorCursor);
Chris@17 614 } else {
Chris@17 615 setCursor(Qt::ArrowCursor);
Chris@17 616 }
Chris@17 617 }
Chris@0 618
Chris@35 619 //!!! if (mode != ViewManager::DrawMode) {
Chris@0 620
Chris@17 621 bool previouslyIdentifying = m_identifyFeatures;
Chris@17 622 m_identifyFeatures = true;
Chris@17 623
Chris@17 624 if (m_identifyFeatures != previouslyIdentifying ||
Chris@17 625 m_identifyPoint != prevPoint) {
Chris@17 626 update();
Chris@17 627 }
Chris@35 628 // }
Chris@0 629
Chris@13 630 return;
Chris@13 631 }
Chris@0 632
Chris@17 633 if (m_navigating || mode == ViewManager::NavigateMode) {
Chris@0 634
Chris@13 635 if (m_shiftPressed) {
Chris@0 636
Chris@13 637 m_mousePos = e->pos();
Chris@13 638 update();
Chris@0 639
Chris@0 640 } else {
Chris@13 641
Chris@20 642 long frameOff = getFrameForX(e->x()) - getFrameForX(m_clickPos.x());
Chris@20 643
Chris@13 644 size_t newCentreFrame = m_dragCentreFrame;
Chris@13 645
Chris@13 646 if (frameOff < 0) {
Chris@13 647 newCentreFrame -= frameOff;
Chris@13 648 } else if (newCentreFrame >= size_t(frameOff)) {
Chris@13 649 newCentreFrame -= frameOff;
Chris@13 650 } else {
Chris@13 651 newCentreFrame = 0;
Chris@13 652 }
Chris@13 653
Chris@13 654 if (newCentreFrame >= getModelsEndFrame()) {
Chris@13 655 newCentreFrame = getModelsEndFrame();
Chris@13 656 if (newCentreFrame > 0) --newCentreFrame;
Chris@13 657 }
Chris@20 658
Chris@20 659 if (getXForFrame(m_centreFrame) != getXForFrame(newCentreFrame)) {
Chris@13 660 setCentreFrame(newCentreFrame);
Chris@13 661 }
Chris@0 662 }
Chris@0 663
Chris@13 664 } else if (mode == ViewManager::SelectMode) {
Chris@13 665
Chris@20 666 int mouseFrame = getFrameForX(e->x());
Chris@13 667 size_t resolution = 1;
Chris@13 668 int snapFrameLeft = mouseFrame;
Chris@13 669 int snapFrameRight = mouseFrame;
Chris@13 670
Chris@13 671 Layer *layer = getSelectedLayer();
Chris@13 672 if (layer) {
Chris@44 673 layer->snapToFeatureFrame(this, snapFrameLeft,
Chris@44 674 resolution, Layer::SnapLeft);
Chris@44 675 layer->snapToFeatureFrame(this, snapFrameRight,
Chris@44 676 resolution, Layer::SnapRight);
Chris@13 677 }
Chris@13 678
Chris@37 679 // std::cerr << "snap: frame = " << mouseFrame << ", start frame = " << m_selectionStartFrame << ", left = " << snapFrameLeft << ", right = " << snapFrameRight << std::endl;
Chris@28 680
Chris@13 681 if (snapFrameLeft < 0) snapFrameLeft = 0;
Chris@13 682 if (snapFrameRight < 0) snapFrameRight = 0;
Chris@13 683
Chris@13 684 size_t min, max;
Chris@13 685
Chris@13 686 if (m_selectionStartFrame > snapFrameLeft) {
Chris@13 687 min = snapFrameLeft;
Chris@13 688 max = m_selectionStartFrame;
Chris@13 689 } else if (snapFrameRight > m_selectionStartFrame) {
Chris@13 690 min = m_selectionStartFrame;
Chris@13 691 max = snapFrameRight;
Chris@13 692 } else {
Chris@13 693 min = snapFrameLeft;
Chris@13 694 max = snapFrameRight;
Chris@0 695 }
Chris@0 696
Chris@13 697 if (m_manager) {
Chris@13 698 m_manager->setInProgressSelection(Selection(min, max),
Chris@17 699 !m_resizing && !m_ctrlPressed);
Chris@0 700 }
Chris@15 701
Chris@15 702 bool doScroll = false;
Chris@15 703 if (!m_manager) doScroll = true;
Chris@15 704 if (!m_manager->isPlaying()) doScroll = true;
Chris@15 705 if (m_followPlay != PlaybackScrollContinuous) doScroll = true;
Chris@15 706
Chris@15 707 if (doScroll) {
Chris@13 708 int offset = mouseFrame - getStartFrame();
Chris@13 709 int available = getEndFrame() - getStartFrame();
Chris@15 710 if (offset >= available * 0.95) {
Chris@15 711 int move = int(offset - available * 0.95) + 1;
Chris@14 712 setCentreFrame(m_centreFrame + move);
Chris@15 713 } else if (offset <= available * 0.10) {
Chris@15 714 int move = int(available * 0.10 - offset) + 1;
Chris@14 715 if (m_centreFrame > move) {
Chris@14 716 setCentreFrame(m_centreFrame - move);
Chris@14 717 } else {
Chris@14 718 setCentreFrame(0);
Chris@14 719 }
Chris@13 720 }
Chris@13 721 }
Chris@13 722
Chris@13 723 update();
Chris@17 724
Chris@17 725 } else if (mode == ViewManager::DrawMode) {
Chris@17 726
Chris@17 727 Layer *layer = getSelectedLayer();
Chris@23 728 if (layer && layer->isLayerEditable()) {
Chris@44 729 layer->drawDrag(this, e);
Chris@17 730 }
Chris@18 731
Chris@18 732 } else if (mode == ViewManager::EditMode) {
Chris@18 733
Chris@42 734 if (!editSelectionDrag(e)) {
Chris@42 735 Layer *layer = getSelectedLayer();
Chris@42 736 if (layer && layer->isLayerEditable()) {
Chris@44 737 layer->editDrag(this, e);
Chris@42 738 }
Chris@18 739 }
Chris@0 740 }
Chris@0 741 }
Chris@0 742
Chris@0 743 void
Chris@0 744 Pane::mouseDoubleClickEvent(QMouseEvent *e)
Chris@0 745 {
Chris@0 746 std::cerr << "mouseDoubleClickEvent" << std::endl;
Chris@36 747
Chris@36 748 m_clickPos = e->pos();
Chris@36 749 m_clickedInRange = true;
Chris@36 750 m_shiftPressed = (e->modifiers() & Qt::ShiftModifier);
Chris@36 751 m_ctrlPressed = (e->modifiers() & Qt::ControlModifier);
Chris@36 752
Chris@36 753 ViewManager::ToolMode mode = ViewManager::NavigateMode;
Chris@36 754 if (m_manager) mode = m_manager->getToolMode();
Chris@36 755
Chris@36 756 if (mode == ViewManager::EditMode) {
Chris@36 757
Chris@36 758 Layer *layer = getSelectedLayer();
Chris@36 759 if (layer && layer->isLayerEditable()) {
Chris@44 760 layer->editOpen(this, e);
Chris@36 761 }
Chris@36 762 }
Chris@0 763 }
Chris@0 764
Chris@0 765 void
Chris@0 766 Pane::leaveEvent(QEvent *)
Chris@0 767 {
Chris@0 768 bool previouslyIdentifying = m_identifyFeatures;
Chris@0 769 m_identifyFeatures = false;
Chris@0 770 if (previouslyIdentifying) update();
Chris@0 771 }
Chris@0 772
Chris@0 773 void
Chris@0 774 Pane::wheelEvent(QWheelEvent *e)
Chris@0 775 {
Chris@0 776 //std::cerr << "wheelEvent, delta " << e->delta() << std::endl;
Chris@0 777
Chris@0 778 int count = e->delta();
Chris@0 779
Chris@0 780 if (count > 0) {
Chris@0 781 if (count >= 120) count /= 120;
Chris@0 782 else count = 1;
Chris@0 783 }
Chris@0 784
Chris@0 785 if (count < 0) {
Chris@0 786 if (count <= -120) count /= 120;
Chris@0 787 else count = -1;
Chris@0 788 }
Chris@17 789
Chris@17 790 if (e->modifiers() & Qt::ControlModifier) {
Chris@17 791
Chris@20 792 // Scroll left or right, rapidly
Chris@20 793
Chris@17 794 if (getStartFrame() < 0 &&
Chris@17 795 getEndFrame() >= getModelsEndFrame()) return;
Chris@17 796
Chris@17 797 long delta = ((width() / 2) * count * m_zoomLevel);
Chris@17 798
Chris@17 799 if (int(m_centreFrame) < delta) {
Chris@17 800 setCentreFrame(0);
Chris@17 801 } else if (int(m_centreFrame) - delta >= int(getModelsEndFrame())) {
Chris@17 802 setCentreFrame(getModelsEndFrame());
Chris@17 803 } else {
Chris@17 804 setCentreFrame(m_centreFrame - delta);
Chris@17 805 }
Chris@17 806
Chris@17 807 } else {
Chris@17 808
Chris@20 809 // Zoom in or out
Chris@20 810
Chris@17 811 int newZoomLevel = m_zoomLevel;
Chris@0 812
Chris@17 813 while (count > 0) {
Chris@17 814 if (newZoomLevel <= 2) {
Chris@17 815 newZoomLevel = 1;
Chris@17 816 break;
Chris@17 817 }
Chris@17 818 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel - 1,
Chris@17 819 ZoomConstraint::RoundDown);
Chris@17 820 --count;
Chris@0 821 }
Chris@17 822
Chris@17 823 while (count < 0) {
Chris@17 824 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel + 1,
Chris@17 825 ZoomConstraint::RoundUp);
Chris@17 826 ++count;
Chris@17 827 }
Chris@17 828
Chris@17 829 if (newZoomLevel != m_zoomLevel) {
Chris@17 830 setZoomLevel(newZoomLevel);
Chris@17 831 }
Chris@0 832 }
Chris@0 833
Chris@0 834 emit paneInteractedWith();
Chris@0 835 }
Chris@8 836
Chris@42 837 bool
Chris@42 838 Pane::editSelectionStart(QMouseEvent *e)
Chris@42 839 {
Chris@43 840 if (!m_identifyFeatures ||
Chris@43 841 !m_manager ||
Chris@43 842 m_manager->getToolMode() != ViewManager::EditMode) {
Chris@43 843 return false;
Chris@43 844 }
Chris@43 845
Chris@42 846 bool closeToLeft, closeToRight;
Chris@42 847 Selection s(getSelectionAt(e->x(), closeToLeft, closeToRight));
Chris@42 848 if (s.isEmpty()) return false;
Chris@42 849 m_editingSelection = s;
Chris@42 850 m_editingSelectionEdge = (closeToLeft ? -1 : closeToRight ? 1 : 0);
Chris@42 851 m_mousePos = e->pos();
Chris@42 852 return true;
Chris@42 853 }
Chris@42 854
Chris@42 855 bool
Chris@42 856 Pane::editSelectionDrag(QMouseEvent *e)
Chris@42 857 {
Chris@42 858 if (m_editingSelection.isEmpty()) return false;
Chris@42 859 m_mousePos = e->pos();
Chris@42 860 update();
Chris@42 861 return true;
Chris@42 862 }
Chris@42 863
Chris@42 864 bool
Chris@42 865 Pane::editSelectionEnd(QMouseEvent *e)
Chris@42 866 {
Chris@42 867 if (m_editingSelection.isEmpty()) return false;
Chris@43 868
Chris@43 869 int offset = m_mousePos.x() - m_clickPos.x();
Chris@43 870 Layer *layer = getSelectedLayer();
Chris@43 871
Chris@43 872 if (offset == 0 || !layer) {
Chris@43 873 m_editingSelection = Selection();
Chris@43 874 return true;
Chris@43 875 }
Chris@43 876
Chris@43 877 int p0 = getXForFrame(m_editingSelection.getStartFrame()) + offset;
Chris@43 878 int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset;
Chris@43 879
Chris@43 880 long f0 = getFrameForX(p0);
Chris@43 881 long f1 = getFrameForX(p1);
Chris@43 882
Chris@43 883 Selection newSelection(f0, f1);
Chris@43 884
Chris@43 885 if (m_editingSelectionEdge == 0) {
Chris@43 886
Chris@43 887 layer->moveSelection(m_editingSelection, f0);
Chris@43 888
Chris@43 889 } else {
Chris@43 890
Chris@43 891 if (m_editingSelectionEdge < 0) {
Chris@43 892 f1 = m_editingSelection.getEndFrame();
Chris@43 893 } else {
Chris@43 894 f0 = m_editingSelection.getStartFrame();
Chris@43 895 }
Chris@43 896
Chris@43 897 newSelection = Selection(f0, f1);
Chris@43 898 layer->resizeSelection(m_editingSelection, newSelection);
Chris@43 899 }
Chris@43 900
Chris@43 901 m_manager->removeSelection(m_editingSelection);
Chris@43 902 m_manager->addSelection(newSelection);
Chris@43 903
Chris@42 904 m_editingSelection = Selection();
Chris@42 905 return true;
Chris@42 906 }
Chris@42 907
Chris@13 908 void
Chris@13 909 Pane::toolModeChanged()
Chris@13 910 {
Chris@13 911 ViewManager::ToolMode mode = m_manager->getToolMode();
Chris@13 912 std::cerr << "Pane::toolModeChanged(" << mode << ")" << std::endl;
Chris@13 913
Chris@13 914 switch (mode) {
Chris@13 915
Chris@13 916 case ViewManager::NavigateMode:
Chris@13 917 setCursor(Qt::PointingHandCursor);
Chris@13 918 break;
Chris@13 919
Chris@13 920 case ViewManager::SelectMode:
Chris@13 921 setCursor(Qt::ArrowCursor);
Chris@13 922 break;
Chris@13 923
Chris@13 924 case ViewManager::EditMode:
Chris@19 925 setCursor(Qt::UpArrowCursor);
Chris@13 926 break;
Chris@13 927
Chris@13 928 case ViewManager::DrawMode:
Chris@13 929 setCursor(Qt::CrossCursor);
Chris@13 930 break;
Chris@36 931 /*
Chris@13 932 case ViewManager::TextMode:
Chris@13 933 setCursor(Qt::IBeamCursor);
Chris@13 934 break;
Chris@36 935 */
Chris@13 936 }
Chris@13 937 }
Chris@13 938
Chris@8 939 QString
Chris@8 940 Pane::toXmlString(QString indent, QString extraAttributes) const
Chris@8 941 {
Chris@8 942 return View::toXmlString
Chris@8 943 (indent,
Chris@8 944 QString("type=\"pane\" centreLineVisible=\"%1\" %2")
Chris@8 945 .arg(m_centreLineVisible).arg(extraAttributes));
Chris@8 946 }
Chris@8 947
Chris@0 948
Chris@0 949 #ifdef INCLUDE_MOCFILES
Chris@0 950 #include "Pane.moc.cpp"
Chris@0 951 #endif
Chris@0 952