Pane.cpp

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

Generated on Wed Feb 20 15:45:27 2008 for SonicVisualiser by  doxygen 1.5.1