annotate widgets/Pane.cpp @ 10:8f5b812baaee

* Hook up SV file i/o. You can now save and load sessions. Some problems -- gain is not reloaded correctly for waveforms, reloaded panes are not properly reconnected to the panner, and no doubt plenty of others.
author Chris Cannam
date Tue, 17 Jan 2006 17:45:55 +0000
parents 06bba0b79b1c
children 01849cd277e6
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 A waveform viewer and audio annotation editor.
Chris@5 5 Chris Cannam, Queen Mary University of London, 2005-2006
Chris@0 6
Chris@0 7 This is experimental software. Not for distribution.
Chris@0 8 */
Chris@0 9
Chris@0 10 #include "widgets/Pane.h"
Chris@0 11 #include "base/Layer.h"
Chris@0 12 #include "base/Model.h"
Chris@0 13 #include "base/ZoomConstraint.h"
Chris@0 14 #include "base/RealTime.h"
Chris@0 15 #include "base/Profiler.h"
Chris@0 16
Chris@0 17 #include <QPaintEvent>
Chris@0 18 #include <QPainter>
Chris@0 19 #include <iostream>
Chris@0 20 #include <cmath>
Chris@0 21
Chris@0 22 using std::cerr;
Chris@0 23 using std::endl;
Chris@0 24
Chris@0 25 Pane::Pane(QWidget *w) :
Chris@0 26 View(w, true),
Chris@0 27 m_identifyFeatures(false),
Chris@0 28 m_clickedInRange(false),
Chris@0 29 m_shiftPressed(false),
Chris@0 30 m_centreLineVisible(true)
Chris@0 31 {
Chris@0 32 setObjectName("Pane");
Chris@0 33 setMouseTracking(true);
Chris@0 34 }
Chris@0 35
Chris@0 36 bool
Chris@0 37 Pane::shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos)
Chris@0 38 {
Chris@0 39 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
Chris@0 40 --vi;
Chris@0 41 if (layer != *vi) return false;
Chris@0 42 pos = m_identifyPoint;
Chris@0 43 return m_identifyFeatures;
Chris@0 44 }
Chris@0 45
Chris@0 46 return false;
Chris@0 47 }
Chris@0 48
Chris@0 49 void
Chris@0 50 Pane::setCentreLineVisible(bool visible)
Chris@0 51 {
Chris@0 52 m_centreLineVisible = visible;
Chris@0 53 update();
Chris@0 54 }
Chris@0 55
Chris@0 56 void
Chris@0 57 Pane::paintEvent(QPaintEvent *e)
Chris@0 58 {
Chris@0 59 QPainter paint;
Chris@0 60
Chris@0 61 QRect r(rect());
Chris@0 62
Chris@0 63 if (e) {
Chris@0 64 r = e->rect();
Chris@0 65 }
Chris@0 66 /*
Chris@0 67 paint.begin(this);
Chris@0 68 paint.setClipRect(r);
Chris@0 69
Chris@0 70 if (hasLightBackground()) {
Chris@0 71 paint.setPen(Qt::white);
Chris@0 72 paint.setBrush(Qt::white);
Chris@0 73 } else {
Chris@0 74 paint.setPen(Qt::black);
Chris@0 75 paint.setBrush(Qt::black);
Chris@0 76 }
Chris@0 77 paint.drawRect(r);
Chris@0 78
Chris@0 79 paint.end();
Chris@0 80 */
Chris@0 81 View::paintEvent(e);
Chris@0 82
Chris@0 83 paint.begin(this);
Chris@0 84
Chris@0 85 if (e) {
Chris@0 86 paint.setClipRect(r);
Chris@0 87 }
Chris@0 88
Chris@0 89 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
Chris@0 90 --vi;
Chris@0 91
Chris@0 92 int sw = (*vi)->getVerticalScaleWidth(paint);
Chris@0 93
Chris@0 94 if (sw > 0 && r.left() < sw) {
Chris@0 95
Chris@0 96 // Profiler profiler("Pane::paintEvent - painting vertical scale", true);
Chris@0 97
Chris@0 98 // std::cerr << "Pane::paintEvent: calling paint.save() in vertical scale block" << std::endl;
Chris@0 99 paint.save();
Chris@0 100
Chris@0 101 paint.setPen(Qt::black);
Chris@0 102 paint.setBrush(Qt::white);
Chris@0 103 paint.drawRect(0, 0, sw, height());
Chris@0 104
Chris@0 105 paint.setBrush(Qt::NoBrush);
Chris@0 106 (*vi)->paintVerticalScale(paint, QRect(0, 0, sw, height()));
Chris@0 107
Chris@0 108 paint.restore();
Chris@0 109 }
Chris@0 110
Chris@0 111 if (m_identifyFeatures) {
Chris@0 112 QRect descRect = (*vi)->getFeatureDescriptionRect(paint,
Chris@0 113 m_identifyPoint);
Chris@0 114 if (descRect.width() > 0 && descRect.height() > 0 &&
Chris@0 115 r.left() + r.width() >= width() - descRect.width() &&
Chris@0 116 r.top() < descRect.height()) {
Chris@0 117
Chris@0 118 // Profiler profiler("Pane::paintEvent - painting local feature description", true);
Chris@0 119
Chris@0 120 // std::cerr << "Pane::paintEvent: calling paint.save() in feature description block" << std::endl;
Chris@0 121 paint.save();
Chris@0 122
Chris@0 123 paint.setPen(Qt::black);
Chris@0 124 paint.setBrush(Qt::white);
Chris@0 125
Chris@0 126 QRect rect(width() - descRect.width() - 1, 0,
Chris@0 127 descRect.width(), descRect.height());
Chris@0 128
Chris@0 129 paint.drawRect(rect);
Chris@0 130
Chris@0 131 paint.setBrush(Qt::NoBrush);
Chris@0 132 (*vi)->paintLocalFeatureDescription(paint, rect, m_identifyPoint);
Chris@0 133
Chris@0 134 paint.restore();
Chris@0 135 }
Chris@0 136 }
Chris@0 137
Chris@0 138 break;
Chris@0 139 }
Chris@0 140
Chris@0 141 if (m_centreLineVisible) {
Chris@0 142
Chris@0 143 if (hasLightBackground()) {
Chris@0 144 paint.setPen(QColor(50, 50, 50));
Chris@0 145 } else {
Chris@0 146 paint.setPen(QColor(200, 200, 200));
Chris@0 147 }
Chris@0 148 paint.setBrush(Qt::NoBrush);
Chris@0 149 paint.drawLine(width() / 2, 0, width() / 2, height() - 1);
Chris@0 150
Chris@0 151 // QFont font(paint.font());
Chris@0 152 // font.setBold(true);
Chris@0 153 // paint.setFont(font);
Chris@0 154
Chris@0 155 int sampleRate = getModelsSampleRate();
Chris@0 156 int y = height() - paint.fontMetrics().height()
Chris@0 157 + paint.fontMetrics().ascent() - 6;
Chris@0 158
Chris@0 159 LayerList::iterator vi = m_layers.end();
Chris@0 160
Chris@0 161 if (vi != m_layers.begin()) {
Chris@0 162
Chris@0 163 switch ((*--vi)->getPreferredFrameCountPosition()) {
Chris@0 164
Chris@0 165 case Layer::PositionTop:
Chris@0 166 y = paint.fontMetrics().ascent() + 6;
Chris@0 167 break;
Chris@0 168
Chris@0 169 case Layer::PositionMiddle:
Chris@0 170 y = (height() - paint.fontMetrics().height()) / 2
Chris@0 171 + paint.fontMetrics().ascent();
Chris@0 172 break;
Chris@0 173
Chris@0 174 case Layer::PositionBottom:
Chris@0 175 // y already set correctly
Chris@0 176 break;
Chris@0 177 }
Chris@0 178 }
Chris@0 179
Chris@0 180 if (sampleRate) {
Chris@0 181
Chris@0 182 QString text(QString::fromStdString
Chris@0 183 (RealTime::frame2RealTime
Chris@0 184 (m_centreFrame, sampleRate).toText(true)));
Chris@0 185
Chris@0 186 int tw = paint.fontMetrics().width(text);
Chris@0 187 int x = width()/2 - 4 - tw;
Chris@0 188
Chris@0 189 if (hasLightBackground()) {
Chris@0 190 paint.setPen(palette().background().color());
Chris@0 191 for (int dx = -1; dx <= 1; ++dx) {
Chris@0 192 for (int dy = -1; dy <= 1; ++dy) {
Chris@0 193 if ((dx && dy) || !(dx || dy)) continue;
Chris@0 194 paint.drawText(x + dx, y + dy, text);
Chris@0 195 }
Chris@0 196 }
Chris@0 197 paint.setPen(QColor(50, 50, 50));
Chris@0 198 } else {
Chris@0 199 paint.setPen(QColor(200, 200, 200));
Chris@0 200 }
Chris@0 201
Chris@0 202 paint.drawText(x, y, text);
Chris@0 203 }
Chris@0 204
Chris@0 205 QString text = QString("%1").arg(m_centreFrame);
Chris@0 206
Chris@0 207 int tw = paint.fontMetrics().width(text);
Chris@0 208 int x = width()/2 + 4;
Chris@0 209
Chris@0 210 if (hasLightBackground()) {
Chris@0 211 paint.setPen(palette().background().color());
Chris@0 212 for (int dx = -1; dx <= 1; ++dx) {
Chris@0 213 for (int dy = -1; dy <= 1; ++dy) {
Chris@0 214 if ((dx && dy) || !(dx || dy)) continue;
Chris@0 215 paint.drawText(x + dx, y + dy, text);
Chris@0 216 }
Chris@0 217 }
Chris@0 218 paint.setPen(QColor(50, 50, 50));
Chris@0 219 } else {
Chris@0 220 paint.setPen(QColor(200, 200, 200));
Chris@0 221 }
Chris@0 222 paint.drawText(x, y, text);
Chris@0 223 }
Chris@0 224
Chris@0 225 if (m_clickedInRange && m_shiftPressed) {
Chris@0 226 paint.setPen(Qt::blue);
Chris@0 227 paint.drawRect(m_clickPos.x(), m_clickPos.y(),
Chris@0 228 m_mousePos.x() - m_clickPos.x(),
Chris@0 229 m_mousePos.y() - m_clickPos.y());
Chris@0 230 }
Chris@0 231
Chris@0 232 paint.end();
Chris@0 233 }
Chris@0 234
Chris@0 235 void
Chris@0 236 Pane::mousePressEvent(QMouseEvent *e)
Chris@0 237 {
Chris@0 238 m_clickPos = e->pos();
Chris@0 239 m_clickedInRange = true;
Chris@0 240 m_shiftPressed = (e->modifiers() & Qt::ShiftModifier);
Chris@0 241 m_dragCentreFrame = m_centreFrame;
Chris@0 242
Chris@0 243 emit paneInteractedWith();
Chris@0 244 }
Chris@0 245
Chris@0 246 void
Chris@0 247 Pane::mouseReleaseEvent(QMouseEvent *e)
Chris@0 248 {
Chris@0 249 if (m_clickedInRange) {
Chris@0 250 mouseMoveEvent(e);
Chris@0 251 }
Chris@0 252 if (m_shiftPressed) {
Chris@0 253
Chris@0 254 int x0 = std::min(m_clickPos.x(), m_mousePos.x());
Chris@0 255 int x1 = std::max(m_clickPos.x(), m_mousePos.x());
Chris@0 256 int w = x1 - x0;
Chris@0 257
Chris@0 258 long newStartFrame = getStartFrame() + m_zoomLevel * x0;
Chris@0 259
Chris@0 260 if (newStartFrame <= -long(width() * m_zoomLevel)) {
Chris@0 261 newStartFrame = -long(width() * m_zoomLevel) + 1;
Chris@0 262 }
Chris@0 263
Chris@0 264 if (newStartFrame >= long(getModelsEndFrame())) {
Chris@0 265 newStartFrame = getModelsEndFrame() - 1;
Chris@0 266 }
Chris@0 267
Chris@0 268 float ratio = float(w) / float(width());
Chris@0 269 // std::cerr << "ratio: " << ratio << std::endl;
Chris@0 270 size_t newZoomLevel = (size_t)nearbyint(m_zoomLevel * ratio);
Chris@0 271 if (newZoomLevel < 1) newZoomLevel = 1;
Chris@0 272
Chris@0 273 // std::cerr << "start: " << m_startFrame << ", level " << m_zoomLevel << std::endl;
Chris@0 274 setZoomLevel(getZoomConstraintBlockSize(newZoomLevel));
Chris@0 275 setStartFrame(newStartFrame);
Chris@0 276
Chris@0 277 //cerr << "mouseReleaseEvent: start frame now " << m_startFrame << endl;
Chris@0 278 // update();
Chris@0 279 }
Chris@0 280 m_clickedInRange = false;
Chris@0 281
Chris@0 282 emit paneInteractedWith();
Chris@0 283 }
Chris@0 284
Chris@0 285 void
Chris@0 286 Pane::mouseMoveEvent(QMouseEvent *e)
Chris@0 287 {
Chris@0 288 if (!m_clickedInRange) {
Chris@0 289
Chris@0 290 // std::cerr << "Pane: calling identifyLocalFeatures" << std::endl;
Chris@0 291
Chris@0 292 //!!! identifyLocalFeatures(true, e->x(), e->y());
Chris@0 293
Chris@0 294 bool previouslyIdentifying = m_identifyFeatures;
Chris@0 295 QPoint prevPoint = m_identifyPoint;
Chris@0 296
Chris@0 297 m_identifyFeatures = true;
Chris@0 298 m_identifyPoint = e->pos();
Chris@0 299
Chris@0 300 if (m_identifyFeatures != previouslyIdentifying ||
Chris@0 301 m_identifyPoint != prevPoint) {
Chris@0 302 update();
Chris@0 303 }
Chris@0 304
Chris@0 305 } else if (m_shiftPressed) {
Chris@0 306
Chris@0 307 m_mousePos = e->pos();
Chris@0 308 update();
Chris@0 309
Chris@0 310 } else {
Chris@0 311
Chris@0 312 long xoff = int(e->x()) - int(m_clickPos.x());
Chris@0 313 long frameOff = xoff * m_zoomLevel;
Chris@0 314
Chris@0 315 size_t newCentreFrame = m_dragCentreFrame;
Chris@0 316
Chris@0 317 if (frameOff < 0) {
Chris@0 318 newCentreFrame -= frameOff;
Chris@0 319 } else if (newCentreFrame >= size_t(frameOff)) {
Chris@0 320 newCentreFrame -= frameOff;
Chris@0 321 } else {
Chris@0 322 newCentreFrame = 0;
Chris@0 323 }
Chris@0 324
Chris@0 325 if (newCentreFrame >= getModelsEndFrame()) {
Chris@0 326 newCentreFrame = getModelsEndFrame();
Chris@0 327 if (newCentreFrame > 0) --newCentreFrame;
Chris@0 328 }
Chris@0 329
Chris@0 330 if (std::max(m_centreFrame, newCentreFrame) -
Chris@0 331 std::min(m_centreFrame, newCentreFrame) > size_t(m_zoomLevel)) {
Chris@0 332 setCentreFrame(newCentreFrame);
Chris@0 333 }
Chris@0 334 }
Chris@0 335 }
Chris@0 336
Chris@0 337 void
Chris@0 338 Pane::mouseDoubleClickEvent(QMouseEvent *e)
Chris@0 339 {
Chris@0 340 std::cerr << "mouseDoubleClickEvent" << std::endl;
Chris@0 341 }
Chris@0 342
Chris@0 343 void
Chris@0 344 Pane::leaveEvent(QEvent *)
Chris@0 345 {
Chris@0 346 bool previouslyIdentifying = m_identifyFeatures;
Chris@0 347 m_identifyFeatures = false;
Chris@0 348 if (previouslyIdentifying) update();
Chris@0 349 }
Chris@0 350
Chris@0 351 void
Chris@0 352 Pane::wheelEvent(QWheelEvent *e)
Chris@0 353 {
Chris@0 354 //std::cerr << "wheelEvent, delta " << e->delta() << std::endl;
Chris@0 355
Chris@0 356 int newZoomLevel = m_zoomLevel;
Chris@0 357
Chris@0 358 int count = e->delta();
Chris@0 359
Chris@0 360 if (count > 0) {
Chris@0 361 if (count >= 120) count /= 120;
Chris@0 362 else count = 1;
Chris@0 363 }
Chris@0 364
Chris@0 365 if (count < 0) {
Chris@0 366 if (count <= -120) count /= 120;
Chris@0 367 else count = -1;
Chris@0 368 }
Chris@0 369
Chris@0 370 while (count > 0) {
Chris@0 371 if (newZoomLevel <= 2) {
Chris@0 372 newZoomLevel = 1;
Chris@0 373 break;
Chris@0 374 }
Chris@0 375 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel - 1,
Chris@0 376 ZoomConstraint::RoundDown);
Chris@0 377 --count;
Chris@0 378 }
Chris@0 379
Chris@0 380 while (count < 0) {
Chris@0 381 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel + 1,
Chris@0 382 ZoomConstraint::RoundUp);
Chris@0 383 ++count;
Chris@0 384 }
Chris@0 385
Chris@0 386 if (newZoomLevel != m_zoomLevel) {
Chris@0 387 setZoomLevel(newZoomLevel);
Chris@0 388 }
Chris@0 389
Chris@0 390 emit paneInteractedWith();
Chris@0 391 }
Chris@8 392
Chris@8 393 QString
Chris@8 394 Pane::toXmlString(QString indent, QString extraAttributes) const
Chris@8 395 {
Chris@8 396 return View::toXmlString
Chris@8 397 (indent,
Chris@8 398 QString("type=\"pane\" centreLineVisible=\"%1\" %2")
Chris@8 399 .arg(m_centreLineVisible).arg(extraAttributes));
Chris@8 400 }
Chris@8 401
Chris@0 402
Chris@0 403 #ifdef INCLUDE_MOCFILES
Chris@0 404 #include "Pane.moc.cpp"
Chris@0 405 #endif
Chris@0 406