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