svgui
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006-2007 Chris Cannam and QMUL. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #include "Pane.h" 00017 #include "layer/Layer.h" 00018 #include "data/model/Model.h" 00019 #include "base/ZoomConstraint.h" 00020 #include "base/RealTime.h" 00021 #include "base/Profiler.h" 00022 #include "ViewManager.h" 00023 #include "widgets/CommandHistory.h" 00024 #include "widgets/TextAbbrev.h" 00025 #include "base/Preferences.h" 00026 #include "layer/WaveformLayer.h" 00027 00028 // GF: added so we can propagate the mouse move event to the note layer for context handling. 00029 #include "layer/LayerFactory.h" 00030 #include "layer/FlexiNoteLayer.h" 00031 00032 00034 #include "data/model/WaveFileModel.h" 00035 00036 #include <QPaintEvent> 00037 #include <QPainter> 00038 #include <QBitmap> 00039 #include <QDragEnterEvent> 00040 #include <QDropEvent> 00041 #include <QCursor> 00042 #include <QTextStream> 00043 #include <QMimeData> 00044 #include <QApplication> 00045 00046 #include <iostream> 00047 #include <cmath> 00048 00050 #include <QFrame> 00051 #include <QGridLayout> 00052 #include <QPushButton> 00053 #include "widgets/Thumbwheel.h" 00054 #include "widgets/Panner.h" 00055 #include "widgets/RangeInputDialog.h" 00056 #include "widgets/NotifyingPushButton.h" 00057 00058 #include "widgets/KeyReference.h" 00059 00060 //#define DEBUG_PANE 00061 00062 00063 00064 00065 QCursor *Pane::m_measureCursor1 = 0; 00066 QCursor *Pane::m_measureCursor2 = 0; 00067 00068 Pane::Pane(QWidget *w) : 00069 View(w, true), 00070 m_identifyFeatures(false), 00071 m_clickedInRange(false), 00072 m_shiftPressed(false), 00073 m_ctrlPressed(false), 00074 m_altPressed(false), 00075 m_navigating(false), 00076 m_resizing(false), 00077 m_editing(false), 00078 m_releasing(false), 00079 m_centreLineVisible(true), 00080 m_scaleWidth(0), 00081 m_pendingWheelAngle(0), 00082 m_headsUpDisplay(0), 00083 m_vpan(0), 00084 m_hthumb(0), 00085 m_vthumb(0), 00086 m_reset(0), 00087 m_mouseInWidget(false), 00088 m_playbackFrameMoveScheduled(false), 00089 m_playbackFrameMoveTo(0) 00090 { 00091 setObjectName("Pane"); 00092 setMouseTracking(true); 00093 setAcceptDrops(true); 00094 00095 updateHeadsUpDisplay(); 00096 00097 connect(this, SIGNAL(regionOutlined(QRect)), 00098 this, SLOT(zoomToRegion(QRect))); 00099 00100 cerr << "Pane::Pane(" << this << ") returning" << endl; 00101 } 00102 00103 void 00104 Pane::updateHeadsUpDisplay() 00105 { 00106 Profiler profiler("Pane::updateHeadsUpDisplay"); 00107 00108 if (!isVisible()) return; 00109 00110 /* 00111 int count = 0; 00112 int currentLevel = 1; 00113 int level = 1; 00114 while (true) { 00115 if (getZoomLevel() == level) currentLevel = count; 00116 int newLevel = getZoomConstraintBlockSize(level + 1, 00117 ZoomConstraint::RoundUp); 00118 if (newLevel == level) break; 00119 if (newLevel == 131072) break; //!!! just because 00120 level = newLevel; 00121 ++count; 00122 } 00123 00124 cerr << "Have " << count+1 << " zoom levels" << endl; 00125 */ 00126 00127 Layer *layer = 0; 00128 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1); 00129 00130 if (!m_headsUpDisplay) { 00131 00132 m_headsUpDisplay = new QFrame(this); 00133 00134 QGridLayout *layout = new QGridLayout; 00135 layout->setMargin(0); 00136 layout->setSpacing(0); 00137 m_headsUpDisplay->setLayout(layout); 00138 00139 m_hthumb = new Thumbwheel(Qt::Horizontal); 00140 m_hthumb->setObjectName(tr("Horizontal Zoom")); 00141 m_hthumb->setCursor(Qt::ArrowCursor); 00142 layout->addWidget(m_hthumb, 1, 0, 1, 2); 00143 m_hthumb->setFixedWidth(70); 00144 m_hthumb->setFixedHeight(16); 00145 m_hthumb->setDefaultValue(0); 00146 m_hthumb->setSpeed(0.6); 00147 connect(m_hthumb, SIGNAL(valueChanged(int)), this, 00148 SLOT(horizontalThumbwheelMoved(int))); 00149 connect(m_hthumb, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); 00150 connect(m_hthumb, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); 00151 00152 m_vpan = new Panner; 00153 m_vpan->setCursor(Qt::ArrowCursor); 00154 layout->addWidget(m_vpan, 0, 1); 00155 m_vpan->setFixedWidth(12); 00156 m_vpan->setFixedHeight(70); 00157 m_vpan->setAlpha(80, 130); 00158 connect(m_vpan, SIGNAL(rectExtentsChanged(float, float, float, float)), 00159 this, SLOT(verticalPannerMoved(float, float, float, float))); 00160 connect(m_vpan, SIGNAL(doubleClicked()), 00161 this, SLOT(editVerticalPannerExtents())); 00162 connect(m_vpan, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); 00163 connect(m_vpan, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); 00164 00165 m_vthumb = new Thumbwheel(Qt::Vertical); 00166 m_vthumb->setObjectName(tr("Vertical Zoom")); 00167 m_vthumb->setCursor(Qt::ArrowCursor); 00168 layout->addWidget(m_vthumb, 0, 2); 00169 m_vthumb->setFixedWidth(16); 00170 m_vthumb->setFixedHeight(70); 00171 connect(m_vthumb, SIGNAL(valueChanged(int)), this, 00172 SLOT(verticalThumbwheelMoved(int))); 00173 connect(m_vthumb, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); 00174 connect(m_vthumb, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); 00175 00176 if (layer) { 00177 RangeMapper *rm = layer->getNewVerticalZoomRangeMapper(); 00178 if (rm) m_vthumb->setRangeMapper(rm); 00179 } 00180 00181 m_reset = new NotifyingPushButton; 00182 m_reset->setFlat(true); 00183 m_reset->setCursor(Qt::ArrowCursor); 00184 m_reset->setFixedHeight(16); 00185 m_reset->setFixedWidth(16); 00186 m_reset->setIcon(QPixmap(":/icons/zoom-reset.png")); 00187 m_reset->setToolTip(tr("Reset zoom to default")); 00188 layout->addWidget(m_reset, 1, 2); 00189 00190 layout->setColumnStretch(0, 20); 00191 00192 connect(m_reset, SIGNAL(clicked()), m_hthumb, SLOT(resetToDefault())); 00193 connect(m_reset, SIGNAL(clicked()), m_vthumb, SLOT(resetToDefault())); 00194 connect(m_reset, SIGNAL(clicked()), m_vpan, SLOT(resetToDefault())); 00195 connect(m_reset, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); 00196 connect(m_reset, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); 00197 } 00198 00199 int count = 0; 00200 int current = 0; 00201 int level = 1; 00202 00204 bool haveConstraint = false; 00205 for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); 00206 ++i) { 00207 if ((*i)->getZoomConstraint() && !(*i)->supportsOtherZoomLevels()) { 00208 haveConstraint = true; 00209 break; 00210 } 00211 } 00212 00213 if (haveConstraint) { 00214 while (true) { 00215 if (getZoomLevel() == level) current = count; 00216 int newLevel = getZoomConstraintBlockSize(level + 1, 00217 ZoomConstraint::RoundUp); 00218 if (newLevel == level) break; 00219 level = newLevel; 00220 if (++count == 50) break; 00221 } 00222 } else { 00223 // if we have no particular constraints, we can really spread out 00224 while (true) { 00225 if (getZoomLevel() >= level) current = count; 00226 int step = level / 10; 00227 int pwr = 0; 00228 while (step > 0) { 00229 ++pwr; 00230 step /= 2; 00231 } 00232 step = 1; 00233 while (pwr > 0) { 00234 step *= 2; 00235 --pwr; 00236 } 00237 // cerr << level << endl; 00238 level += step; 00239 if (++count == 100 || level > 262144) break; 00240 } 00241 } 00242 00243 // cerr << "Have " << count << " zoom levels" << endl; 00244 00245 m_hthumb->setMinimumValue(0); 00246 m_hthumb->setMaximumValue(count); 00247 m_hthumb->setValue(count - current); 00248 00249 // cerr << "set value to " << count-current << endl; 00250 00251 // cerr << "default value is " << m_hthumb->getDefaultValue() << endl; 00252 00253 if (count != 50 && m_hthumb->getDefaultValue() == 0) { 00254 m_hthumb->setDefaultValue(count - current); 00255 // cerr << "set default value to " << m_hthumb->getDefaultValue() << endl; 00256 } 00257 00258 bool haveVThumb = false; 00259 00260 if (layer) { 00261 int defaultStep = 0; 00262 int max = layer->getVerticalZoomSteps(defaultStep); 00263 if (max == 0) { 00264 m_vthumb->hide(); 00265 } else { 00266 haveVThumb = true; 00267 m_vthumb->show(); 00268 m_vthumb->blockSignals(true); 00269 m_vthumb->setMinimumValue(0); 00270 m_vthumb->setMaximumValue(max); 00271 m_vthumb->setDefaultValue(defaultStep); 00272 m_vthumb->setValue(layer->getCurrentVerticalZoomStep()); 00273 m_vthumb->blockSignals(false); 00274 00275 // cerr << "Vertical thumbwheel: min 0, max " << max 00276 // << ", default " << defaultStep << ", value " 00277 // << m_vthumb->getValue() << endl; 00278 00279 } 00280 } 00281 00282 updateVerticalPanner(); 00283 00284 if (m_manager && m_manager->getZoomWheelsEnabled() && 00285 width() > 120 && height() > 100) { 00286 if (!m_headsUpDisplay->isVisible()) { 00287 m_headsUpDisplay->show(); 00288 } 00289 if (haveVThumb) { 00290 m_headsUpDisplay->setFixedHeight(m_vthumb->height() + m_hthumb->height()); 00291 m_headsUpDisplay->move(width() - 86, height() - 86); 00292 } else { 00293 m_headsUpDisplay->setFixedHeight(m_hthumb->height()); 00294 m_headsUpDisplay->move(width() - 86, height() - 16); 00295 } 00296 } else { 00297 m_headsUpDisplay->hide(); 00298 } 00299 } 00300 00301 void 00302 Pane::updateVerticalPanner() 00303 { 00304 if (!m_vpan || !m_manager || !m_manager->getZoomWheelsEnabled()) return; 00305 00306 // In principle we should show or hide the panner on the basis of 00307 // whether the top layer has adjustable display extents, and we do 00308 // that below. However, we have no basis for layout of the panner 00309 // if the vertical scroll wheel is not also present. So if we 00310 // have no vertical scroll wheel, we should remove the panner as 00311 // well. Ideally any layer that implements display extents should 00312 // implement vertical zoom steps as well, but they don't all at 00313 // the moment. 00314 00315 Layer *layer = 0; 00316 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1); 00317 int discard; 00318 if (layer && layer->getVerticalZoomSteps(discard) == 0) { 00319 m_vpan->hide(); 00320 return; 00321 } 00322 00323 float vmin, vmax, dmin, dmax; 00324 if (getTopLayerDisplayExtents(vmin, vmax, dmin, dmax) && vmax != vmin) { 00325 float y0 = (dmin - vmin) / (vmax - vmin); 00326 float y1 = (dmax - vmin) / (vmax - vmin); 00327 m_vpan->blockSignals(true); 00328 m_vpan->setRectExtents(0, 1.0 - y1, 1, y1 - y0); 00329 m_vpan->blockSignals(false); 00330 m_vpan->show(); 00331 } else { 00332 m_vpan->hide(); 00333 } 00334 } 00335 00336 bool 00337 Pane::shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos) const 00338 { 00339 QPoint discard; 00340 bool b0, b1; 00341 00342 if (m_manager && m_manager->getToolModeFor(this) == ViewManager::MeasureMode) { 00343 return false; 00344 } 00345 00346 if (m_manager && !m_manager->shouldIlluminateLocalFeatures()) { 00347 return false; 00348 } 00349 00350 if (layer == getInteractionLayer() && 00351 !shouldIlluminateLocalSelection(discard, b0, b1)) { 00352 00353 pos = m_identifyPoint; 00354 return m_identifyFeatures; 00355 } 00356 00357 return false; 00358 } 00359 00360 bool 00361 Pane::shouldIlluminateLocalSelection(QPoint &pos, 00362 bool &closeToLeft, 00363 bool &closeToRight) const 00364 { 00365 if (m_identifyFeatures && 00366 m_manager && 00367 m_manager->getToolModeFor(this) == ViewManager::EditMode && 00368 !m_manager->getSelections().empty() && 00369 !selectionIsBeingEdited()) { 00370 00371 Selection s(getSelectionAt(m_identifyPoint.x(), 00372 closeToLeft, closeToRight)); 00373 00374 if (!s.isEmpty()) { 00375 if (getInteractionLayer() && getInteractionLayer()->isLayerEditable()) { 00376 00377 pos = m_identifyPoint; 00378 return true; 00379 } 00380 } 00381 } 00382 00383 return false; 00384 } 00385 00386 bool 00387 Pane::selectionIsBeingEdited() const 00388 { 00389 if (!m_editingSelection.isEmpty()) { 00390 if (m_mousePos != m_clickPos && 00391 getFrameForX(m_mousePos.x()) != getFrameForX(m_clickPos.x())) { 00392 return true; 00393 } 00394 } 00395 return false; 00396 } 00397 00398 void 00399 Pane::setCentreLineVisible(bool visible) 00400 { 00401 m_centreLineVisible = visible; 00402 update(); 00403 } 00404 00405 void 00406 Pane::paintEvent(QPaintEvent *e) 00407 { 00408 // Profiler profiler("Pane::paintEvent", true); 00409 00410 QPainter paint; 00411 00412 QRect r(rect()); 00413 if (e) r = e->rect(); 00414 00415 View::paintEvent(e); 00416 00417 paint.begin(this); 00418 setPaintFont(paint); 00419 00420 if (e) paint.setClipRect(r); 00421 00422 ViewManager::ToolMode toolMode = ViewManager::NavigateMode; 00423 if (m_manager) toolMode = m_manager->getToolModeFor(this); 00424 00425 if (m_manager && 00426 m_mouseInWidget && 00427 toolMode == ViewManager::MeasureMode) { 00428 00429 for (LayerList::iterator vi = m_layerStack.end(); vi != m_layerStack.begin(); ) { 00430 --vi; 00431 00432 std::vector<QRect> crosshairExtents; 00433 00434 if ((*vi)->getCrosshairExtents(this, paint, m_identifyPoint, 00435 crosshairExtents)) { 00436 (*vi)->paintCrosshairs(this, paint, m_identifyPoint); 00437 break; 00438 } else if ((*vi)->isLayerOpaque()) { 00439 break; 00440 } 00441 } 00442 } 00443 00444 Layer *topLayer = getTopLayer(); 00445 bool haveSomeTimeXAxis = false; 00446 00447 const Model *waveformModel = 0; // just for reporting purposes 00448 const Model *workModel = 0; 00449 00450 for (LayerList::iterator vi = m_layerStack.end(); vi != m_layerStack.begin(); ) { 00451 --vi; 00452 if (!haveSomeTimeXAxis && (*vi)->hasTimeXAxis()) { 00453 haveSomeTimeXAxis = true; 00454 } 00455 if (dynamic_cast<WaveformLayer *>(*vi)) { 00456 waveformModel = (*vi)->getModel(); 00457 workModel = waveformModel; 00458 } else { 00459 Model *m = (*vi)->getModel(); 00460 if (dynamic_cast<WaveFileModel *>(m)) { 00461 workModel = m; 00462 } else if (m && dynamic_cast<WaveFileModel *>(m->getSourceModel())) { 00463 workModel = m->getSourceModel(); 00464 } 00465 } 00466 00467 if (waveformModel && workModel && haveSomeTimeXAxis) break; 00468 } 00469 00470 m_scaleWidth = 0; 00471 00472 if (workModel && hasTopLayerTimeXAxis()) { 00473 drawModelTimeExtents(r, paint, workModel); 00474 } 00475 00476 if (m_manager && m_manager->shouldShowVerticalScale() && topLayer) { 00477 drawVerticalScale(r, topLayer, paint); 00478 } 00479 00480 if (m_identifyFeatures && 00481 m_manager && m_manager->shouldIlluminateLocalFeatures() && 00482 topLayer) { 00483 drawFeatureDescription(topLayer, paint); 00484 } 00485 00486 int sampleRate = getModelsSampleRate(); 00487 paint.setBrush(Qt::NoBrush); 00488 00489 if (m_centreLineVisible && 00490 m_manager && 00491 m_manager->shouldShowCentreLine()) { 00492 drawCentreLine(sampleRate, paint, !haveSomeTimeXAxis); 00493 } 00494 00495 paint.setPen(QColor(50, 50, 50)); 00496 00497 if (waveformModel && 00498 sampleRate && 00499 m_manager && 00500 m_manager->shouldShowDuration()) { 00501 drawDurationAndRate(r, waveformModel, sampleRate, paint); 00502 } 00503 00504 bool haveWorkTitle = false; 00505 00506 if (workModel && 00507 m_manager && 00508 m_manager->shouldShowWorkTitle()) { 00509 drawWorkTitle(r, paint, workModel); 00510 haveWorkTitle = true; 00511 } 00512 00513 if (workModel && 00514 m_manager && 00515 m_manager->getAlignMode()) { 00516 drawAlignmentStatus(r, paint, workModel, haveWorkTitle); 00517 } 00518 00519 if (m_manager && 00520 m_manager->shouldShowLayerNames()) { 00521 drawLayerNames(r, paint); 00522 } 00523 00524 if (m_shiftPressed && m_clickedInRange && 00525 (toolMode == ViewManager::NavigateMode || m_navigating)) { 00526 00528 //selection block 00529 00530 paint.setPen(Qt::blue); 00532 paint.drawRect(m_clickPos.x(), m_clickPos.y(), 00533 m_mousePos.x() - m_clickPos.x(), 00534 m_mousePos.y() - m_clickPos.y()); 00535 00536 } 00537 00538 if (toolMode == ViewManager::MeasureMode && topLayer) { 00539 bool showFocus = false; 00540 if (!m_manager || !m_manager->isPlaying()) showFocus = true; 00541 topLayer->paintMeasurementRects(this, paint, showFocus, m_identifyPoint); 00542 } 00543 00544 if (selectionIsBeingEdited()) { 00545 drawEditingSelection(paint); 00546 } 00547 00548 paint.end(); 00549 } 00550 00551 int 00552 Pane::getVerticalScaleWidth() const 00553 { 00554 if (m_scaleWidth > 0) return m_scaleWidth; 00555 else return 0; 00556 } 00557 00558 void 00559 Pane::drawVerticalScale(QRect r, Layer *topLayer, QPainter &paint) 00560 { 00561 Layer *scaleLayer = 0; 00562 00563 float min, max; 00564 bool log; 00565 QString unit; 00566 00567 // If the top layer has no scale and reports no display 00568 // extents, but does report a unit, then the scale should be 00569 // drawn from any underlying layer with a scale and that unit. 00570 // If the top layer has no scale and no value extents at all, 00571 // then the scale should be drawn from any underlying layer 00572 // with a scale regardless of unit. 00573 00574 int sw = topLayer->getVerticalScaleWidth 00575 (this, m_manager->shouldShowVerticalColourScale(), paint); 00576 00577 if (sw > 0) { 00578 scaleLayer = topLayer; 00579 m_scaleWidth = sw; 00580 00581 } else { 00582 00583 bool hasDisplayExtents = topLayer->getDisplayExtents(min, max); 00584 bool hasValueExtents = topLayer->getValueExtents(min, max, log, unit); 00585 00586 if (!hasDisplayExtents) { 00587 00588 if (!hasValueExtents) { 00589 00590 for (LayerList::iterator vi = m_layerStack.end(); 00591 vi != m_layerStack.begin(); ) { 00592 00593 --vi; 00594 00595 if ((*vi) == topLayer) continue; 00596 00597 sw = (*vi)->getVerticalScaleWidth 00598 (this, m_manager->shouldShowVerticalColourScale(), paint); 00599 00600 if (sw > 0) { 00601 scaleLayer = *vi; 00602 m_scaleWidth = sw; 00603 break; 00604 } 00605 } 00606 } else if (unit != "") { // && hasValueExtents && !hasDisplayExtents 00607 00608 QString requireUnit = unit; 00609 00610 for (LayerList::iterator vi = m_layerStack.end(); 00611 vi != m_layerStack.begin(); ) { 00612 00613 --vi; 00614 00615 if ((*vi) == topLayer) continue; 00616 00617 if ((*vi)->getDisplayExtents(min, max)) { 00618 00619 // search no further than this: if the 00620 // scale from this layer isn't suitable, 00621 // we'll have to draw no scale (else we'd 00622 // risk ending up with the wrong scale) 00623 00624 if ((*vi)->getValueExtents(min, max, log, unit) && 00625 unit == requireUnit) { 00626 00627 sw = (*vi)->getVerticalScaleWidth 00628 (this, m_manager->shouldShowVerticalColourScale(), paint); 00629 if (sw > 0) { 00630 scaleLayer = *vi; 00631 m_scaleWidth = sw; 00632 } 00633 } 00634 break; 00635 } 00636 } 00637 } 00638 } 00639 } 00640 00641 if (!scaleLayer) m_scaleWidth = 0; 00642 00643 if (m_scaleWidth > 0 && r.left() < m_scaleWidth) { 00644 00645 // Profiler profiler("Pane::paintEvent - painting vertical scale", true); 00646 00647 // SVDEBUG << "Pane::paintEvent: calling paint.save() in vertical scale block" << endl; 00648 paint.save(); 00649 00650 paint.setPen(getForeground()); 00651 paint.setBrush(getBackground()); 00652 paint.drawRect(0, -1, m_scaleWidth, height()+1); 00653 00654 paint.setBrush(Qt::NoBrush); 00655 scaleLayer->paintVerticalScale 00656 (this, m_manager->shouldShowVerticalColourScale(), 00657 paint, QRect(0, 0, m_scaleWidth, height())); 00658 00659 paint.restore(); 00660 } 00661 } 00662 00663 void 00664 Pane::drawFeatureDescription(Layer *topLayer, QPainter &paint) 00665 { 00666 QPoint pos = m_identifyPoint; 00667 QString desc = topLayer->getFeatureDescription(this, pos); 00668 00669 if (desc != "") { 00670 00671 paint.save(); 00672 00673 int tabStop = 00674 paint.fontMetrics().width(tr("Some lengthy prefix:")); 00675 00676 QRect boundingRect = 00677 paint.fontMetrics().boundingRect 00678 (rect(), 00679 Qt::AlignRight | Qt::AlignTop | Qt::TextExpandTabs, 00680 desc, tabStop); 00681 00682 if (hasLightBackground()) { 00683 paint.setPen(Qt::NoPen); 00684 paint.setBrush(QColor(250, 250, 250, 200)); 00685 } else { 00686 paint.setPen(Qt::NoPen); 00687 paint.setBrush(QColor(50, 50, 50, 200)); 00688 } 00689 00690 int extra = paint.fontMetrics().descent(); 00691 paint.drawRect(width() - boundingRect.width() - 10 - extra, 00692 10 - extra, 00693 boundingRect.width() + 2 * extra, 00694 boundingRect.height() + extra); 00695 00696 if (hasLightBackground()) { 00697 paint.setPen(QColor(150, 20, 0)); 00698 } else { 00699 paint.setPen(QColor(255, 150, 100)); 00700 } 00701 00702 QTextOption option; 00703 option.setWrapMode(QTextOption::NoWrap); 00704 option.setAlignment(Qt::AlignRight | Qt::AlignTop); 00705 option.setTabStop(tabStop); 00706 paint.drawText(QRectF(width() - boundingRect.width() - 10, 10, 00707 boundingRect.width(), 00708 boundingRect.height()), 00709 desc, 00710 option); 00711 00712 paint.restore(); 00713 } 00714 } 00715 00716 void 00717 Pane::drawCentreLine(int sampleRate, QPainter &paint, bool omitLine) 00718 { 00719 int fontHeight = paint.fontMetrics().height(); 00720 int fontAscent = paint.fontMetrics().ascent(); 00721 00722 QColor c = QColor(0, 0, 0); 00723 if (!hasLightBackground()) { 00724 c = QColor(240, 240, 240); 00725 } 00726 00727 paint.setPen(c); 00728 int x = width() / 2; 00729 00730 if (!omitLine) { 00731 paint.drawLine(x, 0, x, height() - 1); 00732 paint.drawLine(x-1, 1, x+1, 1); 00733 paint.drawLine(x-2, 0, x+2, 0); 00734 paint.drawLine(x-1, height() - 2, x+1, height() - 2); 00735 paint.drawLine(x-2, height() - 1, x+2, height() - 1); 00736 } 00737 00738 paint.setPen(QColor(50, 50, 50)); 00739 00740 int y = height() - fontHeight + fontAscent - 6; 00741 00742 LayerList::iterator vi = m_layerStack.end(); 00743 00744 if (vi != m_layerStack.begin()) { 00745 00746 switch ((*--vi)->getPreferredFrameCountPosition()) { 00747 00748 case Layer::PositionTop: 00749 y = fontAscent + 6; 00750 break; 00751 00752 case Layer::PositionMiddle: 00753 y = (height() - fontHeight) / 2 00754 + fontAscent; 00755 break; 00756 00757 case Layer::PositionBottom: 00758 // y already set correctly 00759 break; 00760 } 00761 } 00762 00763 if (m_manager && m_manager->shouldShowFrameCount()) { 00764 00765 if (sampleRate) { 00766 00767 QString text(QString::fromStdString 00768 (RealTime::frame2RealTime 00769 (m_centreFrame, sampleRate) 00770 .toText(true))); 00771 00772 int tw = paint.fontMetrics().width(text); 00773 int x = width()/2 - 4 - tw; 00774 00775 drawVisibleText(paint, x, y, text, OutlinedText); 00776 } 00777 00778 QString text = QString("%1").arg(m_centreFrame); 00779 00780 int x = width()/2 + 4; 00781 00782 drawVisibleText(paint, x, y, text, OutlinedText); 00783 } 00784 } 00785 00786 void 00787 Pane::drawModelTimeExtents(QRect r, QPainter &paint, const Model *model) 00788 { 00789 int x0 = getXForFrame(model->getStartFrame()); 00790 int x1 = getXForFrame(model->getEndFrame()); 00791 00792 paint.save(); 00793 00794 QBrush brush; 00795 00796 if (hasLightBackground()) { 00797 brush = QBrush(QColor("#f8f8f8")); 00798 paint.setPen(Qt::black); 00799 } else { 00800 brush = QBrush(QColor("#101010")); 00801 paint.setPen(Qt::white); 00802 } 00803 00804 if (x0 > r.x()) { 00805 paint.fillRect(0, 0, x0, height(), brush); 00806 paint.drawLine(x0, 0, x0, height()); 00807 } 00808 00809 if (x1 < r.x() + r.width()) { 00810 paint.fillRect(x1, 0, width() - x1, height(), brush); 00811 paint.drawLine(x1, 0, x1, height()); 00812 } 00813 00814 paint.restore(); 00815 } 00816 00817 void 00818 Pane::drawAlignmentStatus(QRect r, QPainter &paint, const Model *model, 00819 bool down) 00820 { 00821 const Model *reference = model->getAlignmentReference(); 00822 /* 00823 if (!reference) { 00824 cerr << "Pane[" << this << "]::drawAlignmentStatus: No reference" << endl; 00825 } else if (reference == model) { 00826 cerr << "Pane[" << this << "]::drawAlignmentStatus: This is the reference model" << endl; 00827 } else { 00828 cerr << "Pane[" << this << "]::drawAlignmentStatus: This is not the reference" << endl; 00829 } 00830 */ 00831 QString text; 00832 int completion = 100; 00833 00834 if (reference == model) { 00835 text = tr("Reference"); 00836 } else if (!reference) { 00837 text = tr("Unaligned"); 00838 } else { 00839 completion = model->getAlignmentCompletion(); 00840 if (completion == 0) { 00841 text = tr("Unaligned"); 00842 } else if (completion < 100) { 00843 text = tr("Aligning: %1%").arg(completion); 00844 } else { 00845 text = tr("Aligned"); 00846 } 00847 } 00848 00849 paint.save(); 00850 QFont font(paint.font()); 00851 font.setBold(true); 00852 paint.setFont(font); 00853 if (completion < 100) paint.setBrush(Qt::red); 00854 00855 int y = 5; 00856 if (down) y += paint.fontMetrics().height(); 00857 int w = paint.fontMetrics().width(text); 00858 int h = paint.fontMetrics().height(); 00859 if (r.top() > h + y || r.left() > w + m_scaleWidth + 5) { 00860 paint.restore(); 00861 return; 00862 } 00863 00864 drawVisibleText(paint, m_scaleWidth + 5, 00865 paint.fontMetrics().ascent() + y, text, OutlinedText); 00866 00867 paint.restore(); 00868 } 00869 00870 void 00871 Pane::modelAlignmentCompletionChanged() 00872 { 00873 View::modelAlignmentCompletionChanged(); 00874 update(QRect(0, 0, 300, 100)); 00875 } 00876 00877 void 00878 Pane::drawWorkTitle(QRect r, QPainter &paint, const Model *model) 00879 { 00880 QString title = model->getTitle(); 00881 QString maker = model->getMaker(); 00882 //SVDEBUG << "Pane::drawWorkTitle: title=\"" << title//<< "\", maker=\"" << maker << "\"" << endl; 00883 if (title == "") return; 00884 00885 QString text = title; 00886 if (maker != "") { 00887 text = tr("%1 - %2").arg(title).arg(maker); 00888 } 00889 00890 paint.save(); 00891 QFont font(paint.font()); 00892 font.setItalic(true); 00893 paint.setFont(font); 00894 00895 int y = 5; 00896 int w = paint.fontMetrics().width(text); 00897 int h = paint.fontMetrics().height(); 00898 if (r.top() > h + y || r.left() > w + m_scaleWidth + 5) { 00899 paint.restore(); 00900 return; 00901 } 00902 00903 drawVisibleText(paint, m_scaleWidth + 5, 00904 paint.fontMetrics().ascent() + y, text, OutlinedText); 00905 00906 paint.restore(); 00907 } 00908 00909 void 00910 Pane::drawLayerNames(QRect r, QPainter &paint) 00911 { 00912 int fontHeight = paint.fontMetrics().height(); 00913 int fontAscent = paint.fontMetrics().ascent(); 00914 00915 int lly = height() - 6; 00916 if (m_manager->getZoomWheelsEnabled()) { 00917 lly -= 20; 00918 } 00919 00920 if (r.y() + r.height() < lly - int(m_layerStack.size()) * fontHeight) { 00921 return; 00922 } 00923 00924 QStringList texts; 00925 std::vector<QPixmap> pixmaps; 00926 for (LayerList::iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) { 00927 texts.push_back((*i)->getLayerPresentationName()); 00928 // cerr << "Pane " << this << ": Layer presentation name for " << *i << ": " 00929 // << texts[texts.size()-1] << endl; 00930 pixmaps.push_back((*i)->getLayerPresentationPixmap 00931 (QSize(fontAscent, fontAscent))); 00932 } 00933 00934 int maxTextWidth = width() / 3; 00935 texts = TextAbbrev::abbreviate(texts, paint.fontMetrics(), maxTextWidth); 00936 00937 int llx = width() - maxTextWidth - 5; 00938 if (m_manager->getZoomWheelsEnabled()) { 00939 llx -= 36; 00940 } 00941 00942 if (r.x() + r.width() >= llx - fontAscent - 3) { 00943 00944 for (int i = 0; i < texts.size(); ++i) { 00945 00946 // cerr << "Pane "<< this << ": text " << i << ": " << texts[i] << endl; 00947 00948 if (i + 1 == texts.size()) { 00949 paint.setPen(getForeground()); 00950 } 00951 00952 drawVisibleText(paint, llx, 00953 lly - fontHeight + fontAscent, 00954 texts[i], OutlinedText); 00955 00956 if (!pixmaps[i].isNull()) { 00957 paint.drawPixmap(llx - fontAscent - 3, 00958 lly - fontHeight + (fontHeight-fontAscent)/2, 00959 pixmaps[i]); 00960 } 00961 00962 lly -= fontHeight; 00963 } 00964 } 00965 } 00966 00967 void 00968 Pane::drawEditingSelection(QPainter &paint) 00969 { 00970 int offset = m_mousePos.x() - m_clickPos.x(); 00971 00972 int origStart = m_editingSelection.getStartFrame(); 00973 00974 int p0 = getXForFrame(origStart) + offset; 00975 int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset; 00976 00977 if (m_editingSelectionEdge < 0) { 00978 p1 = getXForFrame(m_editingSelection.getEndFrame()); 00979 } else if (m_editingSelectionEdge > 0) { 00980 p0 = getXForFrame(m_editingSelection.getStartFrame()); 00981 } 00982 00983 int newStart = getFrameForX(p0); 00984 int newEnd = getFrameForX(p1); 00985 00986 paint.save(); 00987 paint.setPen(QPen(getForeground(), 2)); 00988 00989 int fontHeight = paint.fontMetrics().height(); 00990 int fontAscent = paint.fontMetrics().ascent(); 00991 int sampleRate = getModelsSampleRate(); 00992 QString startText, endText, offsetText; 00993 startText = QString("%1").arg(newStart); 00994 endText = QString("%1").arg(newEnd); 00995 offsetText = QString("%1").arg(newStart - origStart); 00996 if (newStart >= origStart) { 00997 offsetText = tr("+%1").arg(offsetText); 00998 } 00999 if (sampleRate) { 01000 startText = QString("%1 / %2") 01001 .arg(QString::fromStdString 01002 (RealTime::frame2RealTime(newStart, sampleRate).toText())) 01003 .arg(startText); 01004 endText = QString("%1 / %2") 01005 .arg(QString::fromStdString 01006 (RealTime::frame2RealTime(newEnd, sampleRate).toText())) 01007 .arg(endText); 01008 offsetText = QString("%1 / %2") 01009 .arg(QString::fromStdString 01010 (RealTime::frame2RealTime(newStart - origStart, sampleRate).toText())) 01011 .arg(offsetText); 01012 if (newStart >= origStart) { 01013 offsetText = tr("+%1").arg(offsetText); 01014 } 01015 } 01016 drawVisibleText(paint, p0 + 2, fontAscent + fontHeight + 4, startText, OutlinedText); 01017 drawVisibleText(paint, p1 + 2, fontAscent + fontHeight + 4, endText, OutlinedText); 01018 drawVisibleText(paint, p0 + 2, fontAscent + fontHeight*2 + 4, offsetText, OutlinedText); 01019 drawVisibleText(paint, p1 + 2, fontAscent + fontHeight*2 + 4, offsetText, OutlinedText); 01020 01022 01023 if (m_editingSelectionEdge < 0) { 01024 paint.drawLine(p0, 1, p1, 1); 01025 paint.drawLine(p0, 0, p0, height()); 01026 paint.drawLine(p0, height() - 1, p1, height() - 1); 01027 } else if (m_editingSelectionEdge > 0) { 01028 paint.drawLine(p0, 1, p1, 1); 01029 paint.drawLine(p1, 0, p1, height()); 01030 paint.drawLine(p0, height() - 1, p1, height() - 1); 01031 } else { 01032 paint.setBrush(Qt::NoBrush); 01033 paint.drawRect(p0, 1, p1 - p0, height() - 2); 01034 } 01035 paint.restore(); 01036 } 01037 01038 void 01039 Pane::drawDurationAndRate(QRect r, const Model *waveformModel, 01040 int sampleRate, QPainter &paint) 01041 { 01042 int fontHeight = paint.fontMetrics().height(); 01043 int fontAscent = paint.fontMetrics().ascent(); 01044 01045 if (r.y() + r.height() < height() - fontHeight - 6) return; 01046 01047 int modelRate = waveformModel->getSampleRate(); 01048 int nativeRate = waveformModel->getNativeRate(); 01049 int playbackRate = m_manager->getPlaybackSampleRate(); 01050 int outputRate = m_manager->getOutputSampleRate(); 01051 01052 QString srNote = ""; 01053 01054 // Show (R) for waveform models that have been resampled or will 01055 // be resampled on playback, and (X) for waveform models that will 01056 // be played at the wrong rate because their rate differs from the 01057 // current playback rate (which is not necessarily that of the 01058 // main model). 01059 01060 if (playbackRate != 0) { 01061 if (modelRate == playbackRate) { 01062 if (modelRate != outputRate || modelRate != nativeRate) { 01063 srNote = " " + tr("(R)"); 01064 } 01065 } else { 01066 srNote = " " + tr("(X)"); 01067 } 01068 } 01069 01070 QString desc = tr("%1 / %2Hz%3") 01071 .arg(RealTime::frame2RealTime(waveformModel->getEndFrame(), 01072 sampleRate) 01073 .toText(false).c_str()) 01074 .arg(nativeRate) 01075 .arg(srNote); 01076 01077 int x = m_scaleWidth + 5; 01078 int pbw = getProgressBarWidth(); 01079 if (x < pbw + 5) x = pbw + 5; 01080 01081 if (r.x() < x + paint.fontMetrics().width(desc)) { 01082 drawVisibleText(paint, x, 01083 height() - fontHeight + fontAscent - 6, 01084 desc, OutlinedText); 01085 } 01086 } 01087 01088 bool 01089 Pane::render(QPainter &paint, int xorigin, int f0, int f1) 01090 { 01091 if (!View::render(paint, xorigin + m_scaleWidth, f0, f1)) { 01092 return false; 01093 } 01094 01095 if (m_scaleWidth > 0) { 01096 01097 Layer *layer = getTopLayer(); 01098 01099 if (layer) { 01100 01101 paint.save(); 01102 01103 paint.setPen(getForeground()); 01104 paint.setBrush(getBackground()); 01105 paint.drawRect(xorigin, -1, m_scaleWidth, height()+1); 01106 01107 paint.setBrush(Qt::NoBrush); 01108 layer->paintVerticalScale 01109 (this, m_manager->shouldShowVerticalColourScale(), 01110 paint, QRect(xorigin, 0, m_scaleWidth, height())); 01111 01112 paint.restore(); 01113 } 01114 } 01115 01116 return true; 01117 } 01118 01119 QImage * 01120 Pane::toNewImage(int f0, int f1) 01121 { 01122 int x0 = f0 / getZoomLevel(); 01123 int x1 = f1 / getZoomLevel(); 01124 01125 QImage *image = new QImage(x1 - x0 + m_scaleWidth, 01126 height(), QImage::Format_RGB32); 01127 01128 int formerScaleWidth = m_scaleWidth; 01129 01130 if (m_manager && m_manager->shouldShowVerticalScale()) { 01131 Layer *layer = getTopLayer(); 01132 if (layer) { 01133 QPainter paint(image); 01134 m_scaleWidth = layer->getVerticalScaleWidth 01135 (this, m_manager->shouldShowVerticalColourScale(), paint); 01136 } 01137 } else { 01138 m_scaleWidth = 0; 01139 } 01140 01141 if (m_scaleWidth != formerScaleWidth) { 01142 delete image; 01143 image = new QImage(x1 - x0 + m_scaleWidth, 01144 height(), QImage::Format_RGB32); 01145 } 01146 01147 QPainter *paint = new QPainter(image); 01148 if (!render(*paint, 0, f0, f1)) { 01149 delete paint; 01150 delete image; 01151 return 0; 01152 } else { 01153 delete paint; 01154 return image; 01155 } 01156 } 01157 01158 QSize 01159 Pane::getImageSize(int f0, int f1) 01160 { 01161 QSize s = View::getImageSize(f0, f1); 01162 QImage *image = new QImage(100, 100, QImage::Format_RGB32); 01163 QPainter paint(image); 01164 01165 int sw = 0; 01166 if (m_manager && m_manager->shouldShowVerticalScale()) { 01167 Layer *layer = getTopLayer(); 01168 if (layer) { 01169 sw = layer->getVerticalScaleWidth 01170 (this, m_manager->shouldShowVerticalColourScale(), paint); 01171 } 01172 } 01173 01174 return QSize(sw + s.width(), s.height()); 01175 } 01176 01177 int 01178 Pane::getFirstVisibleFrame() const 01179 { 01180 int f0 = getFrameForX(m_scaleWidth); 01181 int f = View::getFirstVisibleFrame(); 01182 if (f0 < 0 || f0 < long(f)) return f; 01183 return f0; 01184 } 01185 01186 Selection 01187 Pane::getSelectionAt(int x, bool &closeToLeftEdge, bool &closeToRightEdge) const 01188 { 01189 closeToLeftEdge = closeToRightEdge = false; 01190 01191 if (!m_manager) return Selection(); 01192 01193 int testFrame = getFrameForX(x - 5); 01194 if (testFrame < 0) { 01195 testFrame = getFrameForX(x); 01196 if (testFrame < 0) return Selection(); 01197 } 01198 01199 Selection selection = m_manager->getContainingSelection(testFrame, true); 01200 if (selection.isEmpty()) return selection; 01201 01202 int lx = getXForFrame(selection.getStartFrame()); 01203 int rx = getXForFrame(selection.getEndFrame()); 01204 01205 int fuzz = 2; 01206 if (x < lx - fuzz || x > rx + fuzz) return Selection(); 01207 01208 int width = rx - lx; 01209 fuzz = 3; 01210 if (width < 12) fuzz = width / 4; 01211 if (fuzz < 1) fuzz = 1; 01212 01213 if (x < lx + fuzz) closeToLeftEdge = true; 01214 if (x > rx - fuzz) closeToRightEdge = true; 01215 01216 return selection; 01217 } 01218 01219 bool 01220 Pane::canTopLayerMoveVertical() 01221 { 01222 float vmin, vmax, dmin, dmax; 01223 if (!getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) return false; 01224 if (dmin <= vmin && dmax >= vmax) return false; 01225 return true; 01226 } 01227 01228 bool 01229 Pane::getTopLayerDisplayExtents(float &vmin, float &vmax, 01230 float &dmin, float &dmax, 01231 QString *unit) 01232 { 01233 Layer *layer = getTopLayer(); 01234 if (!layer) return false; 01235 bool vlog; 01236 QString vunit; 01237 bool rv = (layer->getValueExtents(vmin, vmax, vlog, vunit) && 01238 layer->getDisplayExtents(dmin, dmax)); 01239 if (unit) *unit = vunit; 01240 return rv; 01241 } 01242 01243 bool 01244 Pane::setTopLayerDisplayExtents(float dmin, float dmax) 01245 { 01246 Layer *layer = getTopLayer(); 01247 if (!layer) return false; 01248 return layer->setDisplayExtents(dmin, dmax); 01249 } 01250 01251 void 01252 Pane::registerShortcuts(KeyReference &kr) 01253 { 01254 kr.setCategory(tr("Zoom")); 01255 kr.registerAlternativeShortcut(tr("Zoom In"), tr("Wheel Up")); 01256 kr.registerAlternativeShortcut(tr("Zoom Out"), tr("Wheel Down")); 01257 01258 kr.setCategory(tr("General Pane Mouse Actions")); 01259 01260 kr.registerShortcut(tr("Zoom"), tr("Wheel"), 01261 tr("Zoom in or out in time axis")); 01262 kr.registerShortcut(tr("Scroll"), tr("Ctrl+Wheel"), 01263 tr("Scroll rapidly left or right in time axis")); 01264 kr.registerShortcut(tr("Zoom Vertically"), tr("Shift+Wheel"), 01265 tr("Zoom in or out in the vertical axis")); 01266 kr.registerShortcut(tr("Scroll Vertically"), tr("Alt+Wheel"), 01267 tr("Scroll up or down in the vertical axis")); 01268 kr.registerShortcut(tr("Navigate"), tr("Middle"), 01269 tr("Click middle button and drag to navigate with any tool")); 01270 kr.registerShortcut(tr("Relocate"), tr("Double-Click Middle"), 01271 tr("Double-click middle button to relocate with any tool")); 01272 kr.registerShortcut(tr("Menu"), tr("Right"), 01273 tr("Show pane context menu")); 01274 } 01275 01276 Layer * 01277 Pane::getTopFlexiNoteLayer() 01278 { 01279 for (int i = int(m_layerStack.size()) - 1; i >= 0; --i) { 01280 if (LayerFactory::getInstance()->getLayerType(m_layerStack[i]) == 01281 LayerFactory::FlexiNotes) { 01282 return m_layerStack[i]; 01283 } 01284 } 01285 return 0; 01286 } 01287 01288 void 01289 Pane::mousePressEvent(QMouseEvent *e) 01290 { 01291 if (e->buttons() & Qt::RightButton) { 01292 emit contextHelpChanged(""); 01293 emit rightButtonMenuRequested(mapToGlobal(e->pos())); 01294 return; 01295 } 01296 01297 // cerr << "mousePressEvent" << endl; 01298 01299 m_clickPos = e->pos(); 01300 m_mousePos = m_clickPos; 01301 m_clickedInRange = true; 01302 m_editingSelection = Selection(); 01303 m_editingSelectionEdge = 0; 01304 m_shiftPressed = (e->modifiers() & Qt::ShiftModifier); 01305 m_ctrlPressed = (e->modifiers() & Qt::ControlModifier); 01306 m_altPressed = (e->modifiers() & Qt::AltModifier); 01307 m_dragMode = UnresolvedDrag; 01308 01309 ViewManager::ToolMode mode = ViewManager::NavigateMode; 01310 if (m_manager) mode = m_manager->getToolModeFor(this); 01311 01312 m_navigating = false; 01313 m_resizing = false; 01314 m_editing = false; 01315 m_releasing = false; 01316 01317 if (mode == ViewManager::NavigateMode || 01318 (e->buttons() & Qt::MidButton) || 01319 (mode == ViewManager::MeasureMode && 01320 (e->buttons() & Qt::LeftButton) && m_shiftPressed)) { 01321 01322 if (mode != ViewManager::NavigateMode) { 01323 setCursor(Qt::PointingHandCursor); 01324 } 01325 01326 m_navigating = true; 01327 m_dragCentreFrame = m_centreFrame; 01328 m_dragStartMinValue = 0; 01329 01330 float vmin, vmax, dmin, dmax; 01331 if (getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) { 01332 m_dragStartMinValue = dmin; 01333 } 01334 01335 if (m_followPlay == PlaybackScrollPage) { 01336 // Schedule a play-head move to the mouse frame 01337 // location. This will happen only if nothing else of 01338 // interest happens (double-click, drag) before the 01339 // timeout. 01340 schedulePlaybackFrameMove(getFrameForX(e->x())); 01341 } 01342 01343 } else if (mode == ViewManager::SelectMode) { 01344 01345 if (!hasTopLayerTimeXAxis()) return; 01346 01347 bool closeToLeft = false, closeToRight = false; 01348 Selection selection = getSelectionAt(e->x(), closeToLeft, closeToRight); 01349 01350 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) { 01351 01352 m_manager->removeSelection(selection); 01353 01354 if (closeToLeft) { 01355 m_selectionStartFrame = selection.getEndFrame(); 01356 } else { 01357 m_selectionStartFrame = selection.getStartFrame(); 01358 } 01359 01360 m_manager->setInProgressSelection(selection, false); 01361 m_resizing = true; 01362 01363 } else { 01364 01365 int mouseFrame = getFrameForX(e->x()); 01366 int resolution = 1; 01367 int snapFrame = mouseFrame; 01368 01369 Layer *layer = getInteractionLayer(); 01370 if (layer && !m_shiftPressed) { 01371 layer->snapToFeatureFrame(this, snapFrame, 01372 resolution, Layer::SnapLeft); 01373 } 01374 01375 if (snapFrame < 0) snapFrame = 0; 01376 m_selectionStartFrame = snapFrame; 01377 if (m_manager) { 01378 m_manager->setInProgressSelection 01379 (Selection(alignToReference(snapFrame), 01380 alignToReference(snapFrame + resolution)), 01381 !m_ctrlPressed); 01382 } 01383 01384 m_resizing = false; 01385 01386 if (m_followPlay == PlaybackScrollPage) { 01387 // Schedule a play-head move to the mouse frame 01388 // location. This will happen only if nothing else of 01389 // interest happens (double-click, drag) before the 01390 // timeout. 01391 schedulePlaybackFrameMove(mouseFrame); 01392 } 01393 } 01394 01395 update(); 01396 01397 } else if (mode == ViewManager::DrawMode) { 01398 01399 Layer *layer = getInteractionLayer(); 01400 if (layer && layer->isLayerEditable()) { 01401 layer->drawStart(this, e); 01402 } 01403 01404 } else if (mode == ViewManager::EraseMode) { 01405 01406 Layer *layer = getInteractionLayer(); 01407 if (layer && layer->isLayerEditable()) { 01408 layer->eraseStart(this, e); 01409 } 01410 01411 // GF: handle mouse press for NoteEditMode 01412 } else if (mode == ViewManager::NoteEditMode) { 01413 01414 std::cerr << "mouse pressed in note edit mode" << std::endl; 01415 Layer *layer = getTopFlexiNoteLayer(); 01416 if (layer) { 01417 layer->splitStart(this, e); 01418 } 01419 01420 } else if (mode == ViewManager::EditMode) { 01421 01422 // Do nothing here -- we'll do it in mouseMoveEvent when the 01423 // drag threshold has been passed 01424 01425 } else if (mode == ViewManager::MeasureMode) { 01426 01427 Layer *layer = getTopLayer(); 01428 if (layer) layer->measureStart(this, e); 01429 update(); 01430 } 01431 01432 emit paneInteractedWith(); 01433 } 01434 01435 void 01436 Pane::schedulePlaybackFrameMove(int frame) 01437 { 01438 m_playbackFrameMoveTo = frame; 01439 m_playbackFrameMoveScheduled = true; 01440 QTimer::singleShot(QApplication::doubleClickInterval() + 10, this, 01441 SLOT(playbackScheduleTimerElapsed())); 01442 } 01443 01444 void 01445 Pane::playbackScheduleTimerElapsed() 01446 { 01447 if (m_playbackFrameMoveScheduled) { 01448 m_manager->setPlaybackFrame(m_playbackFrameMoveTo); 01449 m_playbackFrameMoveScheduled = false; 01450 } 01451 } 01452 01453 void 01454 Pane::mouseReleaseEvent(QMouseEvent *e) 01455 { 01456 if (e && (e->buttons() & Qt::RightButton)) { 01457 return; 01458 } 01459 01460 // cerr << "mouseReleaseEvent" << endl; 01461 01462 ViewManager::ToolMode mode = ViewManager::NavigateMode; 01463 if (m_manager) mode = m_manager->getToolModeFor(this); 01464 01465 m_releasing = true; 01466 01467 if (m_clickedInRange) { 01468 mouseMoveEvent(e); 01469 } 01470 01471 int mouseFrame = e ? getFrameForX(e->x()) : 0; 01472 if (mouseFrame < 0) mouseFrame = 0; 01473 01474 if (m_navigating || mode == ViewManager::NavigateMode) { 01475 01476 m_navigating = false; 01477 01478 if (mode != ViewManager::NavigateMode) { 01479 // restore cursor 01480 toolModeChanged(); 01481 } 01482 01483 if (m_shiftPressed) { 01484 01485 int x0 = std::min(m_clickPos.x(), m_mousePos.x()); 01486 int x1 = std::max(m_clickPos.x(), m_mousePos.x()); 01487 01488 int y0 = std::min(m_clickPos.y(), m_mousePos.y()); 01489 int y1 = std::max(m_clickPos.y(), m_mousePos.y()); 01490 01491 emit regionOutlined(QRect(x0, y0, x1 - x0, y1 - y0)); 01492 } 01493 01494 } else if (mode == ViewManager::SelectMode) { 01495 01496 if (!hasTopLayerTimeXAxis()) { 01497 m_releasing = false; 01498 return; 01499 } 01500 01501 if (m_manager && m_manager->haveInProgressSelection()) { 01502 01503 //cerr << "JTEST: release with selection" << endl; 01504 bool exclusive; 01505 Selection selection = m_manager->getInProgressSelection(exclusive); 01506 01507 if (selection.getEndFrame() < selection.getStartFrame() + 2) { 01508 selection = Selection(); 01509 } 01510 01511 m_manager->clearInProgressSelection(); 01512 01513 if (exclusive) { 01514 m_manager->setSelection(selection); 01515 } else { 01516 m_manager->addSelection(selection); 01517 } 01518 } 01519 01520 update(); 01521 01522 } else if (mode == ViewManager::DrawMode) { 01523 01524 Layer *layer = getInteractionLayer(); 01525 if (layer && layer->isLayerEditable()) { 01526 layer->drawEnd(this, e); 01527 update(); 01528 } 01529 01530 } else if (mode == ViewManager::EraseMode) { 01531 01532 Layer *layer = getInteractionLayer(); 01533 if (layer && layer->isLayerEditable()) { 01534 layer->eraseEnd(this, e); 01535 update(); 01536 } 01537 01538 } else if (mode == ViewManager::NoteEditMode) { 01539 01540 //GF: handle mouse release for NoteEditMode (note: works but will need to re-think this a bit later) 01541 Layer *layer = getTopFlexiNoteLayer(); 01542 01543 if (layer) { 01544 layer->splitEnd(this, e); 01545 update(); 01546 01547 if (m_editing) { 01548 if (!editSelectionEnd(e)) { 01549 layer->editEnd(this, e); 01550 update(); 01551 } 01552 } 01553 } 01554 01555 } else if (mode == ViewManager::EditMode) { 01556 01557 if (m_editing) { 01558 if (!editSelectionEnd(e)) { 01559 Layer *layer = getInteractionLayer(); 01560 if (layer && layer->isLayerEditable()) { 01561 layer->editEnd(this, e); 01562 update(); 01563 } 01564 } 01565 } 01566 01567 } else if (mode == ViewManager::MeasureMode) { 01568 01569 Layer *layer = getTopLayer(); 01570 if (layer) layer->measureEnd(this, e); 01571 if (m_measureCursor1) setCursor(*m_measureCursor1); 01572 update(); 01573 } 01574 01575 m_clickedInRange = false; 01576 m_releasing = false; 01577 01578 emit paneInteractedWith(); 01579 } 01580 01581 void 01582 Pane::mouseMoveEvent(QMouseEvent *e) 01583 { 01584 if (!e || (e->buttons() & Qt::RightButton)) { 01585 return; 01586 } 01587 01588 // cerr << "mouseMoveEvent" << endl; 01589 01590 QPoint pos = e->pos(); 01591 updateContextHelp(&pos); 01592 01593 if (m_navigating && m_clickedInRange && !m_releasing) { 01594 01595 // if no buttons pressed, and not called from 01596 // mouseReleaseEvent, we want to reset clicked-ness (to avoid 01597 // annoying continual drags when we moved the mouse outside 01598 // the window after pressing button first time). 01599 01600 if (!(e->buttons() & Qt::LeftButton) && 01601 !(e->buttons() & Qt::MidButton)) { 01602 m_clickedInRange = false; 01603 return; 01604 } 01605 } 01606 01607 ViewManager::ToolMode mode = ViewManager::NavigateMode; 01608 if (m_manager) mode = m_manager->getToolModeFor(this); 01609 01610 QPoint prevPoint = m_identifyPoint; 01611 m_identifyPoint = e->pos(); 01612 01613 if (!m_clickedInRange) { 01614 01615 // GF: handle mouse move for context sensitive cursor switching in NoteEditMode. 01616 // GF: Propagate the event to FlexiNoteLayer. I somehow feel it's best handeled there rather than here, but perhaps not if this will be needed elsewhere too. 01617 if (mode == ViewManager::NoteEditMode) { 01618 FlexiNoteLayer *layer = qobject_cast<FlexiNoteLayer *>(getTopFlexiNoteLayer()); 01619 if (layer) { 01620 layer->mouseMoveEvent(this, e); 01621 update(); 01622 // return; 01623 } 01624 } 01625 01626 if (mode == ViewManager::SelectMode && hasTopLayerTimeXAxis()) { 01627 bool closeToLeft = false, closeToRight = false; 01628 getSelectionAt(e->x(), closeToLeft, closeToRight); 01629 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) { 01630 setCursor(Qt::SizeHorCursor); 01631 } else { 01632 setCursor(Qt::ArrowCursor); 01633 } 01634 } 01635 01636 if (m_manager && !m_manager->isPlaying()) { 01637 01638 bool updating = false; 01639 01640 if (getInteractionLayer() && 01641 m_manager->shouldIlluminateLocalFeatures()) { 01642 01643 bool previouslyIdentifying = m_identifyFeatures; 01644 m_identifyFeatures = true; 01645 01646 if (m_identifyFeatures != previouslyIdentifying || 01647 m_identifyPoint != prevPoint) { 01648 update(); 01649 updating = true; 01650 } 01651 } 01652 01653 if (!updating && mode == ViewManager::MeasureMode) { 01654 01655 Layer *layer = getTopLayer(); 01656 if (layer && layer->nearestMeasurementRectChanged 01657 (this, prevPoint, m_identifyPoint)) { 01658 update(); 01659 } 01660 } 01661 } 01662 01663 return; 01664 } 01665 01666 if (m_navigating || mode == ViewManager::NavigateMode) { 01667 01668 if (m_shiftPressed) { 01669 01670 m_mousePos = e->pos(); 01671 update(); 01672 01673 } else { 01674 01675 dragTopLayer(e); 01676 } 01677 01678 } else if (mode == ViewManager::SelectMode) { 01679 01680 if (!hasTopLayerTimeXAxis()) return; 01681 01682 dragExtendSelection(e); 01683 01684 } else if (mode == ViewManager::DrawMode) { 01685 01686 Layer *layer = getInteractionLayer(); 01687 if (layer && layer->isLayerEditable()) { 01688 layer->drawDrag(this, e); 01689 } 01690 01691 } else if (mode == ViewManager::EraseMode) { 01692 01693 Layer *layer = getInteractionLayer(); 01694 if (layer && layer->isLayerEditable()) { 01695 layer->eraseDrag(this, e); 01696 } 01697 01698 // GF: handling NoteEditMode dragging and boundary actions for mouseMoveEvent 01699 } else if (mode == ViewManager::NoteEditMode) { 01700 01701 bool resist = true; 01702 01703 if ((e->modifiers() & Qt::ShiftModifier)) { 01704 m_shiftPressed = true; 01705 } 01706 01707 if (m_shiftPressed) resist = false; 01708 01709 m_dragMode = updateDragMode 01710 (m_dragMode, 01711 m_clickPos, 01712 e->pos(), 01713 true, // can move horiz 01714 true, // can move vert 01715 resist, // resist horiz 01716 resist); // resist vert 01717 01718 if (!m_editing) { 01719 01720 if (m_dragMode != UnresolvedDrag) { 01721 01722 m_editing = true; 01723 01724 QMouseEvent clickEvent(QEvent::MouseButtonPress, 01725 m_clickPos, 01726 Qt::NoButton, 01727 e->buttons(), 01728 e->modifiers()); 01729 01730 if (!editSelectionStart(&clickEvent)) { 01731 Layer *layer = getTopFlexiNoteLayer(); 01732 if (layer) { 01733 std::cerr << "calling edit start" << std::endl; 01734 layer->editStart(this, &clickEvent); 01735 } 01736 } 01737 } 01738 01739 } else { 01740 01741 if (!editSelectionDrag(e)) { 01742 01743 Layer *layer = getInteractionLayer(); 01744 01745 if (layer && layer->isLayerEditable()) { 01746 01747 int x = e->x(); 01748 int y = e->y(); 01749 if (m_dragMode == VerticalDrag) x = m_clickPos.x(); 01750 else if (m_dragMode == HorizontalDrag) y = m_clickPos.y(); 01751 01752 QMouseEvent moveEvent(QEvent::MouseMove, 01753 QPoint(x, y), 01754 Qt::NoButton, 01755 e->buttons(), 01756 e->modifiers()); 01757 std::cerr << "calling editDrag" << std::endl; 01758 layer->editDrag(this, &moveEvent); 01759 } 01760 } 01761 } 01762 01763 } else if (mode == ViewManager::EditMode) { 01764 01765 bool resist = true; 01766 01767 if ((e->modifiers() & Qt::ShiftModifier)) { 01768 m_shiftPressed = true; 01769 // ... but don't set it false if shift has been 01770 // released -- we want the state when we started 01771 // dragging to be used most of the time 01772 } 01773 01774 if (m_shiftPressed) resist = false; 01775 01776 m_dragMode = updateDragMode 01777 (m_dragMode, 01778 m_clickPos, 01779 e->pos(), 01780 true, // can move horiz 01781 true, // can move vert 01782 resist, // resist horiz 01783 resist); // resist vert 01784 01785 if (!m_editing) { 01786 01787 if (m_dragMode != UnresolvedDrag) { 01788 01789 m_editing = true; 01790 01791 QMouseEvent clickEvent(QEvent::MouseButtonPress, 01792 m_clickPos, 01793 Qt::NoButton, 01794 e->buttons(), 01795 e->modifiers()); 01796 01797 if (!editSelectionStart(&clickEvent)) { 01798 Layer *layer = getInteractionLayer(); 01799 if (layer && layer->isLayerEditable()) { 01800 layer->editStart(this, &clickEvent); 01801 } 01802 } 01803 } 01804 01805 } else { 01806 01807 if (!editSelectionDrag(e)) { 01808 01809 Layer *layer = getInteractionLayer(); 01810 01811 if (layer && layer->isLayerEditable()) { 01812 01813 int x = e->x(); 01814 int y = e->y(); 01815 if (m_dragMode == VerticalDrag) x = m_clickPos.x(); 01816 else if (m_dragMode == HorizontalDrag) y = m_clickPos.y(); 01817 01818 QMouseEvent moveEvent(QEvent::MouseMove, 01819 QPoint(x, y), 01820 Qt::NoButton, 01821 e->buttons(), 01822 e->modifiers()); 01823 01824 layer->editDrag(this, &moveEvent); 01825 } 01826 } 01827 } 01828 01829 } else if (mode == ViewManager::MeasureMode) { 01830 01831 if (m_measureCursor2) setCursor(*m_measureCursor2); 01832 01833 Layer *layer = getTopLayer(); 01834 if (layer) { 01835 layer->measureDrag(this, e); 01836 if (layer->hasTimeXAxis()) edgeScrollMaybe(e->x()); 01837 } 01838 01839 update(); 01840 } 01841 01842 if (m_dragMode != UnresolvedDrag) { 01843 m_playbackFrameMoveScheduled = false; 01844 } 01845 } 01846 01847 void 01848 Pane::zoomToRegion(QRect r) 01849 { 01850 int x0 = r.x(); 01851 int y0 = r.y(); 01852 int x1 = r.x() + r.width(); 01853 int y1 = r.y() + r.height(); 01854 01855 int w = x1 - x0; 01856 01857 int newStartFrame = getFrameForX(x0); 01858 01859 int visibleFrames = getEndFrame() - getStartFrame(); 01860 if (newStartFrame <= -visibleFrames) { 01861 newStartFrame = -visibleFrames + 1; 01862 } 01863 01864 if (newStartFrame >= long(getModelsEndFrame())) { 01865 newStartFrame = getModelsEndFrame() - 1; 01866 } 01867 01868 float ratio = float(w) / float(width()); 01869 // cerr << "ratio: " << ratio << endl; 01870 int newZoomLevel = (int)nearbyint(m_zoomLevel * ratio); 01871 if (newZoomLevel < 1) newZoomLevel = 1; 01872 01873 // cerr << "start: " << m_startFrame << ", level " << m_zoomLevel << endl; 01874 setZoomLevel(getZoomConstraintBlockSize(newZoomLevel)); 01875 setStartFrame(newStartFrame); 01876 01877 QString unit; 01878 float min, max; 01879 bool log; 01880 Layer *layer = 0; 01881 for (LayerList::const_iterator i = m_layerStack.begin(); 01882 i != m_layerStack.end(); ++i) { 01883 if ((*i)->getValueExtents(min, max, log, unit) && 01884 (*i)->getDisplayExtents(min, max)) { 01885 layer = *i; 01886 break; 01887 } 01888 } 01889 01890 if (layer) { 01891 if (log) { 01892 min = (min < 0.0) ? -log10f(-min) : (min == 0.0) ? 0.0 : log10f(min); 01893 max = (max < 0.0) ? -log10f(-max) : (max == 0.0) ? 0.0 : log10f(max); 01894 } 01895 float rmin = min + ((max - min) * (height() - y1)) / height(); 01896 float rmax = min + ((max - min) * (height() - y0)) / height(); 01897 cerr << "min: " << min << ", max: " << max << ", y0: " << y0 << ", y1: " << y1 << ", h: " << height() << ", rmin: " << rmin << ", rmax: " << rmax << endl; 01898 if (log) { 01899 rmin = powf(10, rmin); 01900 rmax = powf(10, rmax); 01901 } 01902 cerr << "finally: rmin: " << rmin << ", rmax: " << rmax << " " << unit << endl; 01903 01904 layer->setDisplayExtents(rmin, rmax); 01905 updateVerticalPanner(); 01906 } 01907 } 01908 01909 void 01910 Pane::dragTopLayer(QMouseEvent *e) 01911 { 01912 // We need to avoid making it too easy to drag both 01913 // horizontally and vertically, in the case where the 01914 // mouse is moved "mostly" in horizontal or vertical axis 01915 // with only a small variation in the other axis. This is 01916 // particularly important during playback (when we want to 01917 // avoid small horizontal motions) or in slow refresh 01918 // layers like spectrogram (when we want to avoid small 01919 // vertical motions). 01920 // 01921 // To this end we have horizontal and vertical thresholds 01922 // and a series of states: unresolved, horizontally or 01923 // vertically constrained, free. 01924 // 01925 // When the mouse first moves, we're unresolved: we 01926 // restrict ourselves to whichever direction seems safest, 01927 // until the mouse has passed a small threshold distance 01928 // from the click point. Then we lock in to one of the 01929 // constrained modes, based on which axis that distance 01930 // was measured in first. Finally, if it turns out we've 01931 // also moved more than a certain larger distance in the 01932 // other direction as well, we may switch into free mode. 01933 // 01934 // If the top layer is incapable of being dragged 01935 // vertically, the logic is short circuited. 01936 01937 m_dragMode = updateDragMode 01938 (m_dragMode, 01939 m_clickPos, 01940 e->pos(), 01941 true, // can move horiz 01942 canTopLayerMoveVertical(), // can move vert 01943 canTopLayerMoveVertical() || (m_manager && m_manager->isPlaying()), // resist horiz 01944 !(m_manager && m_manager->isPlaying())); // resist vert 01945 01946 if (m_dragMode == HorizontalDrag || 01947 m_dragMode == FreeDrag) { 01948 01949 int frameOff = getFrameForX(e->x()) - getFrameForX(m_clickPos.x()); 01950 int newCentreFrame = m_dragCentreFrame; 01951 01952 if (frameOff < 0) { 01953 newCentreFrame -= frameOff; 01954 } else if (newCentreFrame >= frameOff) { 01955 newCentreFrame -= frameOff; 01956 } else { 01957 newCentreFrame = 0; 01958 } 01959 01960 #ifdef DEBUG_PANE 01961 SVDEBUG << "Pane::dragTopLayer: newCentreFrame = " << newCentreFrame << 01962 ", models end frame = " << getModelsEndFrame() << endl; 01963 #endif 01964 01965 if (newCentreFrame >= getModelsEndFrame()) { 01966 newCentreFrame = getModelsEndFrame(); 01967 if (newCentreFrame > 0) --newCentreFrame; 01968 } 01969 01970 if (getXForFrame(m_centreFrame) != getXForFrame(newCentreFrame)) { 01971 setCentreFrame(newCentreFrame, !m_altPressed); 01972 } 01973 } 01974 01975 if (m_dragMode == VerticalDrag || 01976 m_dragMode == FreeDrag) { 01977 01978 float vmin = 0.f, vmax = 0.f; 01979 float dmin = 0.f, dmax = 0.f; 01980 01981 if (getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) { 01982 01983 // cerr << "ydiff = " << ydiff << endl; 01984 01985 int ydiff = e->y() - m_clickPos.y(); 01986 float perpix = (dmax - dmin) / height(); 01987 float valdiff = ydiff * perpix; 01988 // cerr << "valdiff = " << valdiff << endl; 01989 01990 if (m_dragMode == UnresolvedDrag && ydiff != 0) { 01991 m_dragMode = VerticalDrag; 01992 } 01993 01994 float newmin = m_dragStartMinValue + valdiff; 01995 float newmax = m_dragStartMinValue + (dmax - dmin) + valdiff; 01996 if (newmin < vmin) { 01997 newmax += vmin - newmin; 01998 newmin += vmin - newmin; 01999 } 02000 if (newmax > vmax) { 02001 newmin -= newmax - vmax; 02002 newmax -= newmax - vmax; 02003 } 02004 // cerr << "(" << dmin << ", " << dmax << ") -> (" 02005 // << newmin << ", " << newmax << ") (drag start " << m_dragStartMinValue << ")" << endl; 02006 02007 setTopLayerDisplayExtents(newmin, newmax); 02008 updateVerticalPanner(); 02009 } 02010 } 02011 } 02012 02013 Pane::DragMode 02014 Pane::updateDragMode(DragMode dragMode, 02015 QPoint origin, 02016 QPoint point, 02017 bool canMoveHorizontal, 02018 bool canMoveVertical, 02019 bool resistHorizontal, 02020 bool resistVertical) 02021 { 02022 int xdiff = point.x() - origin.x(); 02023 int ydiff = point.y() - origin.y(); 02024 02025 int smallThreshold = 10, bigThreshold = 80; 02026 02027 // SVDEBUG << "Pane::updateDragMode: xdiff = " << xdiff << ", ydiff = " 02028 // << ydiff << ", canMoveVertical = " << canMoveVertical << ", drag mode = " << m_dragMode << endl; 02029 02030 if (dragMode == UnresolvedDrag) { 02031 02032 if (abs(ydiff) > smallThreshold && 02033 abs(ydiff) > abs(xdiff) * 2 && 02034 canMoveVertical) { 02035 // SVDEBUG << "Pane::updateDragMode: passed vertical threshold" << endl; 02036 dragMode = VerticalDrag; 02037 } else if (abs(xdiff) > smallThreshold && 02038 abs(xdiff) > abs(ydiff) * 2 && 02039 canMoveHorizontal) { 02040 // SVDEBUG << "Pane::updateDragMode: passed horizontal threshold" << endl; 02041 dragMode = HorizontalDrag; 02042 } else if (abs(xdiff) > smallThreshold && 02043 abs(ydiff) > smallThreshold && 02044 canMoveVertical && 02045 canMoveHorizontal) { 02046 // SVDEBUG << "Pane::updateDragMode: passed both thresholds" << endl; 02047 dragMode = FreeDrag; 02048 } 02049 } 02050 02051 if (dragMode == VerticalDrag && canMoveHorizontal) { 02052 if (abs(xdiff) > bigThreshold) dragMode = FreeDrag; 02053 } 02054 02055 if (dragMode == HorizontalDrag && canMoveVertical) { 02056 if (abs(ydiff) > bigThreshold) dragMode = FreeDrag; 02057 } 02058 02059 if (dragMode == UnresolvedDrag) { 02060 if (!resistHorizontal && xdiff != 0) { 02061 dragMode = HorizontalDrag; 02062 } 02063 if (!resistVertical && ydiff != 0) { 02064 if (dragMode == HorizontalDrag) dragMode = FreeDrag; 02065 else dragMode = VerticalDrag; 02066 } 02067 } 02068 02069 return dragMode; 02070 } 02071 02072 void 02073 Pane::dragExtendSelection(QMouseEvent *e) 02074 { 02075 int mouseFrame = getFrameForX(e->x()); 02076 int resolution = 1; 02077 int snapFrameLeft = mouseFrame; 02078 int snapFrameRight = mouseFrame; 02079 02080 Layer *layer = getInteractionLayer(); 02081 if (layer && !m_shiftPressed) { 02082 layer->snapToFeatureFrame(this, snapFrameLeft, 02083 resolution, Layer::SnapLeft); 02084 layer->snapToFeatureFrame(this, snapFrameRight, 02085 resolution, Layer::SnapRight); 02086 } 02087 02088 // cerr << "snap: frame = " << mouseFrame << ", start frame = " << m_selectionStartFrame << ", left = " << snapFrameLeft << ", right = " << snapFrameRight << endl; 02089 02090 if (snapFrameLeft < 0) snapFrameLeft = 0; 02091 if (snapFrameRight < 0) snapFrameRight = 0; 02092 02093 int min, max; 02094 02095 if (m_selectionStartFrame > snapFrameLeft) { 02096 min = snapFrameLeft; 02097 max = m_selectionStartFrame; 02098 } else if (snapFrameRight > m_selectionStartFrame) { 02099 min = m_selectionStartFrame; 02100 max = snapFrameRight; 02101 } else { 02102 min = snapFrameLeft; 02103 max = snapFrameRight; 02104 } 02105 02106 if (m_manager) { 02107 m_manager->setInProgressSelection(Selection(alignToReference(min), 02108 alignToReference(max)), 02109 !m_resizing && !m_ctrlPressed); 02110 } 02111 02112 edgeScrollMaybe(e->x()); 02113 02114 update(); 02115 02116 if (min != max) { 02117 m_playbackFrameMoveScheduled = false; 02118 } 02119 } 02120 02121 void 02122 Pane::edgeScrollMaybe(int x) 02123 { 02124 int mouseFrame = getFrameForX(x); 02125 02126 bool doScroll = false; 02127 if (!m_manager) doScroll = true; 02128 else if (!m_manager->isPlaying()) doScroll = true; 02129 02130 if (m_followPlay != PlaybackScrollContinuous) doScroll = true; 02131 02132 if (doScroll) { 02133 int offset = mouseFrame - getStartFrame(); 02134 int available = getEndFrame() - getStartFrame(); 02135 int move = 0; 02136 if (offset >= available * 0.95) { 02137 move = int(offset - available * 0.95) + 1; 02138 } else if (offset <= available * 0.10) { 02139 move = int(available * 0.10 - offset) + 1; 02140 move = -move; 02141 } 02142 if (move != 0) { 02143 setCentreFrame(m_centreFrame + move); 02144 update(); 02145 } 02146 } 02147 } 02148 02149 void 02150 Pane::mouseDoubleClickEvent(QMouseEvent *e) 02151 { 02152 if (e->buttons() & Qt::RightButton) { 02153 return; 02154 } 02155 02156 cerr << "mouseDoubleClickEvent" << endl; 02157 02158 m_clickPos = e->pos(); 02159 m_clickedInRange = true; 02160 m_shiftPressed = (e->modifiers() & Qt::ShiftModifier); 02161 m_ctrlPressed = (e->modifiers() & Qt::ControlModifier); 02162 m_altPressed = (e->modifiers() & Qt::AltModifier); 02163 02164 // cancel any pending move that came from a single click 02165 m_playbackFrameMoveScheduled = false; 02166 02167 ViewManager::ToolMode mode = ViewManager::NavigateMode; 02168 if (m_manager) mode = m_manager->getToolModeFor(this); 02169 02170 bool relocate = (mode == ViewManager::NavigateMode || 02171 (e->buttons() & Qt::MidButton)); 02172 02173 if (mode == ViewManager::SelectMode) { 02174 m_clickedInRange = false; 02175 if (m_manager) m_manager->clearInProgressSelection(); 02176 emit doubleClickSelectInvoked(getFrameForX(e->x())); 02177 return; 02178 } 02179 02180 if (mode == ViewManager::NavigateMode || 02181 mode == ViewManager::EditMode) { 02182 02183 Layer *layer = getInteractionLayer(); 02184 if (layer && layer->isLayerEditable()) { 02185 if (layer->editOpen(this, e)) relocate = false; 02186 } 02187 02188 } else if (mode == ViewManager::MeasureMode) { 02189 02190 Layer *layer = getTopLayer(); 02191 if (layer) layer->measureDoubleClick(this, e); 02192 update(); 02193 } 02194 02195 if (relocate) { 02196 02197 int f = getFrameForX(e->x()); 02198 02199 setCentreFrame(f); 02200 02201 m_dragCentreFrame = f; 02202 m_dragStartMinValue = 0; 02203 m_dragMode = UnresolvedDrag; 02204 02205 float vmin, vmax, dmin, dmax; 02206 if (getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) { 02207 m_dragStartMinValue = dmin; 02208 } 02209 } 02210 02211 if (mode == ViewManager::NoteEditMode) { 02212 std::cerr << "double click in note edit mode" << std::endl; 02213 Layer *layer = getInteractionLayer(); 02214 if (layer && layer->isLayerEditable()) { 02215 layer->addNote(this, e); 02216 } 02217 } 02218 02219 m_clickedInRange = false; // in case mouseReleaseEvent is not properly called 02220 } 02221 02222 void 02223 Pane::enterEvent(QEvent *) 02224 { 02225 m_mouseInWidget = true; 02226 } 02227 02228 void 02229 Pane::leaveEvent(QEvent *) 02230 { 02231 m_mouseInWidget = false; 02232 bool previouslyIdentifying = m_identifyFeatures; 02233 m_identifyFeatures = false; 02234 if (previouslyIdentifying) update(); 02235 emit contextHelpChanged(""); 02236 } 02237 02238 void 02239 Pane::resizeEvent(QResizeEvent *) 02240 { 02241 updateHeadsUpDisplay(); 02242 } 02243 02244 void 02245 Pane::wheelEvent(QWheelEvent *e) 02246 { 02247 cerr << "wheelEvent, delta " << e->delta() << ", angleDelta " << e->angleDelta().x() << "," << e->angleDelta().y() << ", pixelDelta " << e->pixelDelta().x() << "," << e->pixelDelta().y() << ", modifiers " << e->modifiers() << endl; 02248 02249 int dx = e->angleDelta().x(); 02250 int dy = e->angleDelta().y(); 02251 02252 if (dx == 0 && dy == 0) { 02253 return; 02254 } 02255 02256 int d = dy; 02257 bool horizontal = false; 02258 02259 if (abs(dx) > abs(dy)) { 02260 d = dx; 02261 horizontal = true; 02262 } else if (e->modifiers() & Qt::ControlModifier) { 02263 // treat a vertical wheel as horizontal 02264 horizontal = true; 02265 } 02266 02267 if (e->phase() == Qt::ScrollBegin || 02268 fabs(d) >= 120 || 02269 (d > 0 && m_pendingWheelAngle < 0) || 02270 (d < 0 && m_pendingWheelAngle > 0)) { 02271 m_pendingWheelAngle = d; 02272 } else { 02273 m_pendingWheelAngle += d; 02274 } 02275 02276 if (horizontal && e->pixelDelta().x() != 0) { 02277 02278 // Have fine pixel information: use it 02279 02280 wheelHorizontalFine(e->pixelDelta().x(), e->modifiers()); 02281 02282 m_pendingWheelAngle = 0; 02283 02284 } else { 02285 02286 // Coarse wheel information (or vertical zoom, which is 02287 // necessarily coarse itself) 02288 02289 while (abs(m_pendingWheelAngle) >= 120) { 02290 02291 int sign = (m_pendingWheelAngle < 0 ? -1 : 1); 02292 02293 if (horizontal) { 02294 wheelHorizontal(sign, e->modifiers()); 02295 } else { 02296 wheelVertical(sign, e->modifiers()); 02297 } 02298 02299 m_pendingWheelAngle -= sign * 120; 02300 } 02301 } 02302 } 02303 02304 void 02305 Pane::wheelVertical(int sign, Qt::KeyboardModifiers mods) 02306 { 02307 cerr << "wheelVertical: sign = " << sign << endl; 02308 02309 if (mods & Qt::ShiftModifier) { 02310 02311 // Pan vertically 02312 02313 if (m_vpan) { 02314 m_vpan->scroll(sign > 0); 02315 } 02316 02317 } else if (mods & Qt::AltModifier) { 02318 02319 // Zoom vertically 02320 02321 if (m_vthumb) { 02322 m_vthumb->scroll(sign > 0); 02323 } 02324 02325 } else { 02326 02327 // Zoom in or out 02328 02329 int newZoomLevel = m_zoomLevel; 02330 02331 if (sign > 0) { 02332 if (newZoomLevel <= 2) { 02333 newZoomLevel = 1; 02334 } else { 02335 newZoomLevel = getZoomConstraintBlockSize 02336 (newZoomLevel - 1, ZoomConstraint::RoundDown); 02337 } 02338 } else { // sign < 0 02339 newZoomLevel = getZoomConstraintBlockSize 02340 (newZoomLevel + 1, ZoomConstraint::RoundUp); 02341 } 02342 02343 if (newZoomLevel != m_zoomLevel) { 02344 setZoomLevel(newZoomLevel); 02345 } 02346 } 02347 02348 emit paneInteractedWith(); 02349 } 02350 02351 void 02352 Pane::wheelHorizontal(int sign, Qt::KeyboardModifiers mods) 02353 { 02354 cerr << "wheelHorizontal: sign = " << sign << endl; 02355 02356 // Scroll left or right, rapidly 02357 02358 wheelHorizontalFine((width() / 4) * sign, mods); 02359 } 02360 02361 void 02362 Pane::wheelHorizontalFine(int pixels, Qt::KeyboardModifiers) 02363 { 02364 cerr << "wheelHorizontalFine: pixels = " << pixels << endl; 02365 02366 // Scroll left or right by a fixed number of pixels 02367 02368 if (getStartFrame() < 0 && 02369 getEndFrame() >= getModelsEndFrame()) return; 02370 02371 int delta = (pixels * m_zoomLevel); 02372 02373 if (m_centreFrame < delta) { 02374 setCentreFrame(0); 02375 } else if (m_centreFrame - delta >= getModelsEndFrame()) { 02376 setCentreFrame(getModelsEndFrame()); 02377 } else { 02378 setCentreFrame(m_centreFrame - delta); 02379 } 02380 02381 emit paneInteractedWith(); 02382 } 02383 02384 void 02385 Pane::horizontalThumbwheelMoved(int value) 02386 { 02388 02389 int count = 0; 02390 int level = 1; 02391 02392 02394 bool haveConstraint = false; 02395 for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); 02396 ++i) { 02397 if ((*i)->getZoomConstraint() && !(*i)->supportsOtherZoomLevels()) { 02398 haveConstraint = true; 02399 break; 02400 } 02401 } 02402 02403 if (haveConstraint) { 02404 while (true) { 02405 if (m_hthumb->getMaximumValue() - value == count) break; 02406 int newLevel = getZoomConstraintBlockSize(level + 1, 02407 ZoomConstraint::RoundUp); 02408 if (newLevel == level) break; 02409 level = newLevel; 02410 if (++count == 50) break; 02411 } 02412 } else { 02413 while (true) { 02414 if (m_hthumb->getMaximumValue() - value == count) break; 02415 int step = level / 10; 02416 int pwr = 0; 02417 while (step > 0) { 02418 ++pwr; 02419 step /= 2; 02420 } 02421 step = 1; 02422 while (pwr > 0) { 02423 step *= 2; 02424 --pwr; 02425 } 02426 // cerr << level << endl; 02427 level += step; 02428 if (++count == 100 || level > 262144) break; 02429 } 02430 } 02431 02432 // cerr << "new level is " << level << endl; 02433 setZoomLevel(level); 02434 } 02435 02436 void 02437 Pane::verticalThumbwheelMoved(int value) 02438 { 02439 Layer *layer = 0; 02440 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1); 02441 if (layer) { 02442 int defaultStep = 0; 02443 int max = layer->getVerticalZoomSteps(defaultStep); 02444 if (max == 0) { 02445 updateHeadsUpDisplay(); 02446 return; 02447 } 02448 if (value > max) { 02449 value = max; 02450 } 02451 layer->setVerticalZoomStep(value); 02452 updateVerticalPanner(); 02453 } 02454 } 02455 02456 void 02457 Pane::verticalPannerMoved(float , float y0, float , float h) 02458 { 02459 float vmin, vmax, dmin, dmax; 02460 if (!getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) return; 02461 float y1 = y0 + h; 02462 float newmax = vmin + ((1.0 - y0) * (vmax - vmin)); 02463 float newmin = vmin + ((1.0 - y1) * (vmax - vmin)); 02464 // cerr << "verticalPannerMoved: (" << x0 << "," << y0 << "," << w 02465 // << "," << h << ") -> (" << newmin << "," << newmax << ")" << endl; 02466 setTopLayerDisplayExtents(newmin, newmax); 02467 } 02468 02469 void 02470 Pane::editVerticalPannerExtents() 02471 { 02472 if (!m_vpan || !m_manager || !m_manager->getZoomWheelsEnabled()) return; 02473 02474 float vmin, vmax, dmin, dmax; 02475 QString unit; 02476 if (!getTopLayerDisplayExtents(vmin, vmax, dmin, dmax, &unit) 02477 || vmax == vmin) { 02478 return; 02479 } 02480 02481 RangeInputDialog dialog(tr("Enter new range"), 02482 tr("New vertical display range, from %1 to %2 %4:") 02483 .arg(vmin).arg(vmax).arg(unit), 02484 unit, vmin, vmax, this); 02485 dialog.setRange(dmin, dmax); 02486 02487 if (dialog.exec() == QDialog::Accepted) { 02488 dialog.getRange(dmin, dmax); 02489 setTopLayerDisplayExtents(dmin, dmax); 02490 updateVerticalPanner(); 02491 } 02492 } 02493 02494 void 02495 Pane::layerParametersChanged() 02496 { 02497 View::layerParametersChanged(); 02498 updateHeadsUpDisplay(); 02499 } 02500 02501 void 02502 Pane::dragEnterEvent(QDragEnterEvent *e) 02503 { 02504 QStringList formats(e->mimeData()->formats()); 02505 cerr << "dragEnterEvent: format: " 02506 << formats.join(",") 02507 << ", possibleActions: " << e->possibleActions() 02508 << ", proposedAction: " << e->proposedAction() << endl; 02509 02510 if (e->mimeData()->hasFormat("text/uri-list") || 02511 e->mimeData()->hasFormat("text/plain")) { 02512 02513 if (e->proposedAction() & Qt::CopyAction) { 02514 e->acceptProposedAction(); 02515 } else { 02516 e->setDropAction(Qt::CopyAction); 02517 e->accept(); 02518 } 02519 } 02520 } 02521 02522 void 02523 Pane::dropEvent(QDropEvent *e) 02524 { 02525 cerr << "dropEvent: text: \"" << e->mimeData()->text() 02526 << "\"" << endl; 02527 02528 if (e->mimeData()->hasFormat("text/uri-list") || 02529 e->mimeData()->hasFormat("text/plain")) { 02530 02531 if (e->proposedAction() & Qt::CopyAction) { 02532 e->acceptProposedAction(); 02533 } else { 02534 e->setDropAction(Qt::CopyAction); 02535 e->accept(); 02536 } 02537 02538 if (e->mimeData()->hasFormat("text/uri-list")) { 02539 02540 SVDEBUG << "accepting... data is \"" << e->mimeData()->data("text/uri-list").data() << "\"" << endl; 02541 emit dropAccepted(QString::fromLocal8Bit 02542 (e->mimeData()->data("text/uri-list").data()) 02543 .split(QRegExp("[\\r\\n]+"), 02544 QString::SkipEmptyParts)); 02545 } else { 02546 emit dropAccepted(QString::fromLocal8Bit 02547 (e->mimeData()->data("text/plain").data())); 02548 } 02549 } 02550 } 02551 02552 bool 02553 Pane::editSelectionStart(QMouseEvent *e) 02554 { 02555 if (!m_identifyFeatures || 02556 !m_manager || 02557 m_manager->getToolModeFor(this) != ViewManager::EditMode) { 02558 return false; 02559 } 02560 02561 bool closeToLeft, closeToRight; 02562 Selection s(getSelectionAt(e->x(), closeToLeft, closeToRight)); 02563 if (s.isEmpty()) return false; 02564 m_editingSelection = s; 02565 m_editingSelectionEdge = (closeToLeft ? -1 : closeToRight ? 1 : 0); 02566 m_mousePos = e->pos(); 02567 return true; 02568 } 02569 02570 bool 02571 Pane::editSelectionDrag(QMouseEvent *e) 02572 { 02573 if (m_editingSelection.isEmpty()) return false; 02574 m_mousePos = e->pos(); 02575 update(); 02576 return true; 02577 } 02578 02579 bool 02580 Pane::editSelectionEnd(QMouseEvent *) 02581 { 02582 if (m_editingSelection.isEmpty()) return false; 02583 02584 int offset = m_mousePos.x() - m_clickPos.x(); 02585 Layer *layer = getInteractionLayer(); 02586 02587 if (offset == 0 || !layer) { 02588 m_editingSelection = Selection(); 02589 return true; 02590 } 02591 02592 int p0 = getXForFrame(m_editingSelection.getStartFrame()) + offset; 02593 int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset; 02594 02595 int f0 = getFrameForX(p0); 02596 int f1 = getFrameForX(p1); 02597 02598 Selection newSelection(f0, f1); 02599 02600 if (m_editingSelectionEdge == 0) { 02601 02602 CommandHistory::getInstance()->startCompoundOperation 02603 (tr("Drag Selection"), true); 02604 02605 layer->moveSelection(m_editingSelection, f0); 02606 02607 } else { 02608 02609 CommandHistory::getInstance()->startCompoundOperation 02610 (tr("Resize Selection"), true); 02611 02612 if (m_editingSelectionEdge < 0) { 02613 f1 = m_editingSelection.getEndFrame(); 02614 } else { 02615 f0 = m_editingSelection.getStartFrame(); 02616 } 02617 02618 newSelection = Selection(f0, f1); 02619 layer->resizeSelection(m_editingSelection, newSelection); 02620 } 02621 02622 m_manager->removeSelection(m_editingSelection); 02623 m_manager->addSelection(newSelection); 02624 02625 CommandHistory::getInstance()->endCompoundOperation(); 02626 02627 m_editingSelection = Selection(); 02628 return true; 02629 } 02630 02631 void 02632 Pane::toolModeChanged() 02633 { 02634 ViewManager::ToolMode mode = m_manager->getToolModeFor(this); 02635 // SVDEBUG << "Pane::toolModeChanged(" << mode << ")" << endl; 02636 02637 if (mode == ViewManager::MeasureMode && !m_measureCursor1) { 02638 m_measureCursor1 = new QCursor(QBitmap(":/icons/measure1cursor.xbm"), 02639 QBitmap(":/icons/measure1mask.xbm"), 02640 15, 14); 02641 m_measureCursor2 = new QCursor(QBitmap(":/icons/measure2cursor.xbm"), 02642 QBitmap(":/icons/measure2mask.xbm"), 02643 16, 17); 02644 } 02645 02646 switch (mode) { 02647 02648 case ViewManager::NavigateMode: 02649 setCursor(Qt::PointingHandCursor); 02650 break; 02651 02652 case ViewManager::SelectMode: 02653 setCursor(Qt::ArrowCursor); 02654 break; 02655 02656 case ViewManager::EditMode: 02657 setCursor(Qt::UpArrowCursor); 02658 break; 02659 02660 case ViewManager::DrawMode: 02661 setCursor(Qt::CrossCursor); 02662 break; 02663 02664 case ViewManager::EraseMode: 02665 setCursor(Qt::CrossCursor); 02666 break; 02667 02668 case ViewManager::MeasureMode: 02669 if (m_measureCursor1) setCursor(*m_measureCursor1); 02670 break; 02671 02672 // GF: NoteEditMode uses the same default cursor as EditMode, but it will change in a context sensitive manner. 02673 case ViewManager::NoteEditMode: 02674 setCursor(Qt::UpArrowCursor); 02675 break; 02676 02677 /* 02678 case ViewManager::TextMode: 02679 setCursor(Qt::IBeamCursor); 02680 break; 02681 */ 02682 } 02683 } 02684 02685 void 02686 Pane::zoomWheelsEnabledChanged() 02687 { 02688 updateHeadsUpDisplay(); 02689 update(); 02690 } 02691 02692 void 02693 Pane::viewZoomLevelChanged(View *v, int z, bool locked) 02694 { 02695 // cerr << "Pane[" << this << "]::zoomLevelChanged (global now " 02696 // << (m_manager ? m_manager->getGlobalZoom() : 0) << ")" << endl; 02697 02698 View::viewZoomLevelChanged(v, z, locked); 02699 02700 if (m_hthumb && !m_hthumb->isVisible()) return; 02701 02702 if (v != this) { 02703 if (!locked || !m_followZoom) return; 02704 } 02705 02706 if (m_manager && m_manager->getZoomWheelsEnabled()) { 02707 updateHeadsUpDisplay(); 02708 } 02709 } 02710 02711 void 02712 Pane::propertyContainerSelected(View *v, PropertyContainer *pc) 02713 { 02714 Layer *layer = 0; 02715 02716 if (getLayerCount() > 0) { 02717 layer = getLayer(getLayerCount() - 1); 02718 disconnect(layer, SIGNAL(verticalZoomChanged()), 02719 this, SLOT(verticalZoomChanged())); 02720 } 02721 02722 View::propertyContainerSelected(v, pc); 02723 updateHeadsUpDisplay(); 02724 02725 if (m_vthumb) { 02726 RangeMapper *rm = 0; 02727 if (layer) rm = layer->getNewVerticalZoomRangeMapper(); 02728 if (rm) m_vthumb->setRangeMapper(rm); 02729 } 02730 02731 if (getLayerCount() > 0) { 02732 layer = getLayer(getLayerCount() - 1); 02733 connect(layer, SIGNAL(verticalZoomChanged()), 02734 this, SLOT(verticalZoomChanged())); 02735 } 02736 } 02737 02738 void 02739 Pane::verticalZoomChanged() 02740 { 02741 Layer *layer = 0; 02742 02743 if (getLayerCount() > 0) { 02744 02745 layer = getLayer(getLayerCount() - 1); 02746 02747 if (m_vthumb && m_vthumb->isVisible()) { 02748 m_vthumb->setValue(layer->getCurrentVerticalZoomStep()); 02749 } 02750 } 02751 } 02752 02753 void 02754 Pane::updateContextHelp(const QPoint *pos) 02755 { 02756 QString help = ""; 02757 02758 if (m_clickedInRange) { 02759 emit contextHelpChanged(""); 02760 return; 02761 } 02762 02763 ViewManager::ToolMode mode = ViewManager::NavigateMode; 02764 if (m_manager) mode = m_manager->getToolModeFor(this); 02765 02766 bool editable = false; 02767 Layer *layer = getInteractionLayer(); 02768 if (layer && layer->isLayerEditable()) { 02769 editable = true; 02770 } 02771 02772 if (mode == ViewManager::NavigateMode) { 02773 02774 help = tr("Click and drag to navigate"); 02775 02776 } else if (mode == ViewManager::SelectMode) { 02777 02778 if (!hasTopLayerTimeXAxis()) return; 02779 02780 bool haveSelection = (m_manager && !m_manager->getSelections().empty()); 02781 02782 if (haveSelection) { 02783 #ifdef Q_OS_MAC 02784 if (editable) { 02785 help = tr("Click and drag to select a range; hold Shift to avoid snapping to items; hold Cmd for multi-select; middle-click and drag to navigate"); 02786 } else { 02787 help = tr("Click and drag to select a range; hold Cmd for multi-select; middle-click and drag to navigate"); 02788 } 02789 #else 02790 if (editable) { 02791 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"); 02792 } else { 02793 help = tr("Click and drag to select a range; hold Ctrl for multi-select; middle-click and drag to navigate"); 02794 } 02795 #endif 02796 02797 if (pos) { 02798 bool closeToLeft = false, closeToRight = false; 02799 Selection selection = getSelectionAt(pos->x(), closeToLeft, closeToRight); 02800 if ((closeToLeft || closeToRight) && !(closeToLeft && closeToRight)) { 02801 02802 help = tr("Click and drag to move the selection boundary"); 02803 } 02804 } 02805 } else { 02806 if (editable) { 02807 help = tr("Click and drag to select a range; hold Shift to avoid snapping to items; middle-click to navigate"); 02808 } else { 02809 help = tr("Click and drag to select a range; middle-click and drag to navigate"); 02810 } 02811 } 02812 02813 } else if (mode == ViewManager::DrawMode) { 02814 02816 if (editable) { 02817 help = tr("Click to add a new item in the active layer"); 02818 } 02819 02820 } else if (mode == ViewManager::EraseMode) { 02821 02823 if (editable) { 02824 help = tr("Click to erase an item from the active layer"); 02825 } 02826 02827 } else if (mode == ViewManager::EditMode) { 02828 02830 if (editable) { 02831 help = tr("Click and drag an item in the active layer to move it; hold Shift to override initial resistance"); 02832 if (pos) { 02833 bool closeToLeft = false, closeToRight = false; 02834 Selection selection = getSelectionAt(pos->x(), closeToLeft, closeToRight); 02835 if (!selection.isEmpty()) { 02836 help = tr("Click and drag to move all items in the selected range"); 02837 } 02838 } 02839 } 02840 } 02841 02842 emit contextHelpChanged(help); 02843 } 02844 02845 void 02846 Pane::mouseEnteredWidget() 02847 { 02848 QWidget *w = dynamic_cast<QWidget *>(sender()); 02849 if (!w) return; 02850 02851 if (w == m_vpan) { 02852 emit contextHelpChanged(tr("Click and drag to adjust the visible range of the vertical scale")); 02853 } else if (w == m_vthumb) { 02854 emit contextHelpChanged(tr("Click and drag to adjust the vertical zoom level")); 02855 } else if (w == m_hthumb) { 02856 emit contextHelpChanged(tr("Click and drag to adjust the horizontal zoom level")); 02857 } else if (w == m_reset) { 02858 emit contextHelpChanged(tr("Reset horizontal and vertical zoom levels to their defaults")); 02859 } 02860 } 02861 02862 void 02863 Pane::mouseLeftWidget() 02864 { 02865 emit contextHelpChanged(""); 02866 } 02867 02868 void 02869 Pane::toXml(QTextStream &stream, 02870 QString indent, QString extraAttributes) const 02871 { 02872 View::toXml 02873 (stream, indent, 02874 QString("type=\"pane\" centreLineVisible=\"%1\" height=\"%2\" %3") 02875 .arg(m_centreLineVisible).arg(height()).arg(extraAttributes)); 02876 } 02877 02878