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