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