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