Mercurial > hg > svgui
comparison layer/ImageLayer.cpp @ 304:4b7e8da8f069
* More work on image layer display &c
author | Chris Cannam |
---|---|
date | Fri, 05 Oct 2007 13:27:21 +0000 |
parents | 46faec7aae12 |
children | 013a37723c0a |
comparison
equal
deleted
inserted
replaced
303:46faec7aae12 | 304:4b7e8da8f069 |
---|---|
108 } | 108 } |
109 | 109 |
110 bool | 110 bool |
111 ImageLayer::isLayerScrollable(const View *v) const | 111 ImageLayer::isLayerScrollable(const View *v) const |
112 { | 112 { |
113 QPoint discard; | 113 return true; |
114 return !v->shouldIlluminateLocalFeatures(this, discard); | |
115 } | 114 } |
116 | 115 |
117 | 116 |
118 ImageModel::PointList | 117 ImageModel::PointList |
119 ImageLayer::getLocalPoints(View *v, int x, int y) const | 118 ImageLayer::getLocalPoints(View *v, int x, int y) const |
120 { | 119 { |
121 if (!m_model) return ImageModel::PointList(); | 120 if (!m_model) return ImageModel::PointList(); |
122 | 121 |
123 std::cerr << "ImageLayer::getLocalPoints(" << x << "," << y << "):"; | 122 // std::cerr << "ImageLayer::getLocalPoints(" << x << "," << y << "):"; |
124 | 123 const ImageModel::PointList &points(m_model->getPoints()); |
125 long frame0 = v->getFrameForX(-150); | |
126 long frame1 = v->getFrameForX(v->width() + 150); | |
127 | |
128 ImageModel::PointList points(m_model->getPoints(frame0, frame1)); | |
129 | 124 |
130 ImageModel::PointList rv; | 125 ImageModel::PointList rv; |
131 | 126 |
132 //!!! need to store drawn size as well as original size for each | 127 for (ImageModel::PointList::const_iterator i = points.begin(); |
133 //image, but for now: | 128 i != points.end(); ) { |
134 | |
135 for (ImageModel::PointList::iterator i = points.begin(); | |
136 i != points.end(); ++i) { | |
137 | 129 |
138 const ImageModel::Point &p(*i); | 130 const ImageModel::Point &p(*i); |
139 | |
140 int px = v->getXForFrame(p.frame); | 131 int px = v->getXForFrame(p.frame); |
141 | 132 if (px > x) break; |
142 if (x >= px && x < px + 100) { | 133 |
134 ++i; | |
135 if (i != points.end()) { | |
136 int nx = v->getXForFrame((*i).frame); | |
137 if (nx < x) { | |
138 // as we aim not to overlap the images, if the following | |
139 // image begins to the left of a point then the current | |
140 // one may be assumed to end to the left of it as well. | |
141 continue; | |
142 } | |
143 } | |
144 | |
145 // this image is a candidate, test it properly | |
146 | |
147 int width = 32; | |
148 if (m_scaled[v].find(p.image) != m_scaled[v].end()) { | |
149 width = m_scaled[v][p.image].width(); | |
150 std::cerr << "scaled width = " << width << std::endl; | |
151 } | |
152 | |
153 if (x >= px && x < px + width) { | |
143 rv.insert(p); | 154 rv.insert(p); |
144 } | 155 } |
145 } | 156 } |
146 | 157 |
147 std::cerr << rv.size() << " point(s)" << std::endl; | 158 // std::cerr << rv.size() << " point(s)" << std::endl; |
148 | 159 |
149 return rv; | 160 return rv; |
150 } | 161 } |
151 | 162 |
152 QString | 163 QString |
268 int sampleRate = m_model->getSampleRate(); | 279 int sampleRate = m_model->getSampleRate(); |
269 if (!sampleRate) return; | 280 if (!sampleRate) return; |
270 | 281 |
271 // Profiler profiler("ImageLayer::paint", true); | 282 // Profiler profiler("ImageLayer::paint", true); |
272 | 283 |
273 int x0 = rect.left(), x1 = rect.right(); | 284 // int x0 = rect.left(), x1 = rect.right(); |
285 int x0 = 0, x1 = v->width(); | |
286 | |
274 long frame0 = v->getFrameForX(x0); | 287 long frame0 = v->getFrameForX(x0); |
275 long frame1 = v->getFrameForX(x1); | 288 long frame1 = v->getFrameForX(x1); |
276 | 289 |
277 ImageModel::PointList points(m_model->getPoints(frame0, frame1)); | 290 ImageModel::PointList points(m_model->getPoints(frame0, frame1)); |
278 if (points.empty()) return; | 291 if (points.empty()) return; |
279 | 292 |
293 paint.save(); | |
294 paint.setClipRect(rect.x(), 0, rect.width(), v->height()); | |
295 | |
280 QColor penColour; | 296 QColor penColour; |
281 penColour = v->getForeground(); | 297 penColour = v->getForeground(); |
282 | 298 |
283 // std::cerr << "ImageLayer::paint: resolution is " | 299 QColor brushColour; |
284 // << m_model->getResolution() << " frames" << std::endl; | 300 brushColour = v->getBackground(); |
285 | 301 |
286 QPoint localPos; | 302 int h, s, val; |
287 long illuminateFrame = -1; | 303 brushColour.getHsv(&h, &s, &val); |
288 | 304 brushColour.setHsv(h, s, 255, 240); |
289 if (v->shouldIlluminateLocalFeatures(this, localPos)) { | 305 |
290 ImageModel::PointList localPoints = getLocalPoints(v, localPos.x(), | 306 paint.setPen(penColour); |
291 localPos.y()); | 307 paint.setBrush(brushColour); |
292 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame; | 308 paint.setRenderHint(QPainter::Antialiasing, true); |
293 } | 309 |
294 | |
295 paint.save(); | |
296 paint.setClipRect(rect.x(), 0, rect.width(), v->height()); | |
297 | |
298 for (ImageModel::PointList::const_iterator i = points.begin(); | 310 for (ImageModel::PointList::const_iterator i = points.begin(); |
299 i != points.end(); ++i) { | 311 i != points.end(); ++i) { |
300 | 312 |
301 const ImageModel::Point &p(*i); | 313 const ImageModel::Point &p(*i); |
302 | 314 |
307 ++j; | 319 ++j; |
308 if (j != points.end()) { | 320 if (j != points.end()) { |
309 int jx = v->getXForFrame(j->frame); | 321 int jx = v->getXForFrame(j->frame); |
310 if (jx < nx) nx = jx; | 322 if (jx < nx) nx = jx; |
311 } | 323 } |
312 /* | 324 |
313 if (illuminateFrame == p.frame) { | 325 drawImage(v, paint, p, x, nx); |
314 paint.setBrush(penColour); | 326 } |
315 paint.setPen(v->getBackground()); | 327 |
316 } else { | 328 paint.setRenderHint(QPainter::Antialiasing, false); |
317 paint.setPen(penColour); | |
318 paint.setBrush(brushColour); | |
319 } | |
320 */ | |
321 QString label = p.label; | |
322 QString imageName = p.image; | |
323 | |
324 int nw = nx - x; | |
325 if (nw < 10) nw = 20; | |
326 | |
327 int top = 10; | |
328 if (v->height() < 50) top = 5; | |
329 | |
330 int bottom = top; | |
331 | |
332 QRect labelRect; | |
333 if (label != "") { | |
334 float aspect = getImageAspect(imageName); | |
335 int iw = lrintf((v->height() - v->height()/4 - top - bottom) | |
336 * aspect); | |
337 labelRect = paint.fontMetrics().boundingRect | |
338 (QRect(0, 0, iw, v->height()/4), | |
339 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, label); | |
340 bottom += labelRect.height() + 5; | |
341 } | |
342 | |
343 QImage image = getImage(v, | |
344 imageName, | |
345 QSize(nw, v->height() - top - bottom)); | |
346 | |
347 if (image.isNull()) { | |
348 image = QImage(":icons/emptypage.png"); | |
349 } | |
350 | |
351 paint.setRenderHint(QPainter::Antialiasing, false); | |
352 | |
353 int boxWidth = image.width(); | |
354 | |
355 if (label != "") { | |
356 boxWidth = std::max(boxWidth, labelRect.width()); | |
357 } | |
358 | |
359 paint.drawRect(x-1, top-1, boxWidth+1, v->height() - 2 * top +1); | |
360 | |
361 paint.setRenderHint(QPainter::Antialiasing, true); | |
362 | |
363 paint.drawImage(x + (boxWidth - image.width())/2, top, image); | |
364 | |
365 paint.drawText(QRect(x, v->height() - bottom + 5, | |
366 boxWidth, labelRect.height()), | |
367 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, | |
368 label); | |
369 } | |
370 | |
371 paint.restore(); | 329 paint.restore(); |
372 paint.setRenderHint(QPainter::Antialiasing, false); | 330 } |
331 | |
332 void | |
333 ImageLayer::drawImage(View *v, QPainter &paint, const ImageModel::Point &p, | |
334 int x, int nx) const | |
335 { | |
336 QString label = p.label; | |
337 QString imageName = p.image; | |
338 | |
339 QImage image; | |
340 QString additionalText; | |
341 | |
342 QSize imageSize; | |
343 if (!getImageOriginalSize(imageName, imageSize)) { | |
344 image = QImage(":icons/emptypage.png"); | |
345 imageSize = image.size(); | |
346 additionalText = imageName; | |
347 } | |
348 | |
349 int topMargin = 10; | |
350 int bottomMargin = 10; | |
351 int spacing = 5; | |
352 | |
353 if (v->height() < 100) { | |
354 topMargin = 5; | |
355 bottomMargin = 5; | |
356 } | |
357 | |
358 int maxBoxHeight = v->height() - topMargin - bottomMargin; | |
359 | |
360 int availableWidth = nx - x - 3; | |
361 if (availableWidth < 20) availableWidth = 20; | |
362 | |
363 QRect labelRect; | |
364 | |
365 if (label != "") { | |
366 | |
367 int likelyHeight = v->height() / 4; | |
368 | |
369 int likelyWidth = // available height times image aspect | |
370 ((maxBoxHeight - likelyHeight) * imageSize.width()) | |
371 / imageSize.height(); | |
372 | |
373 if (likelyWidth > imageSize.width()) { | |
374 likelyWidth = imageSize.width(); | |
375 } | |
376 | |
377 if (likelyWidth > availableWidth) { | |
378 likelyWidth = availableWidth; | |
379 } | |
380 | |
381 int singleWidth = paint.fontMetrics().width(label); | |
382 if (singleWidth < availableWidth && singleWidth < likelyWidth * 2) { | |
383 likelyWidth = singleWidth + 4; | |
384 } | |
385 | |
386 labelRect = paint.fontMetrics().boundingRect | |
387 (QRect(0, 0, likelyWidth, likelyHeight), | |
388 Qt::AlignCenter | Qt::TextWordWrap, label); | |
389 | |
390 labelRect.setWidth(labelRect.width() + 6); | |
391 } | |
392 | |
393 if (image.isNull()) { | |
394 image = getImage(v, imageName, | |
395 QSize(availableWidth, | |
396 maxBoxHeight - labelRect.height())); | |
397 } | |
398 | |
399 int boxWidth = image.width(); | |
400 if (boxWidth < labelRect.width()) { | |
401 boxWidth = labelRect.width(); | |
402 } | |
403 | |
404 int boxHeight = image.height(); | |
405 if (label != "") { | |
406 boxHeight += labelRect.height() + spacing; | |
407 } | |
408 | |
409 int division = image.height(); | |
410 | |
411 if (additionalText != "") { | |
412 | |
413 paint.save(); | |
414 | |
415 QFont font(paint.font()); | |
416 font.setItalic(true); | |
417 paint.setFont(font); | |
418 | |
419 int tw = paint.fontMetrics().width(additionalText); | |
420 if (tw > availableWidth) { | |
421 tw = availableWidth; | |
422 } | |
423 if (boxWidth < tw) { | |
424 boxWidth = tw; | |
425 } | |
426 boxHeight += paint.fontMetrics().height(); | |
427 division += paint.fontMetrics().height(); | |
428 } | |
429 | |
430 bottomMargin = v->height() - topMargin - boxHeight; | |
431 if (bottomMargin > topMargin + v->height()/7) { | |
432 topMargin += v->height()/8; | |
433 bottomMargin -= v->height()/8; | |
434 } | |
435 | |
436 paint.drawRect(x - 1, | |
437 topMargin - 1, | |
438 boxWidth + 2, | |
439 boxHeight + 2); | |
440 | |
441 int imageY; | |
442 if (label != "") { | |
443 imageY = topMargin + labelRect.height() + spacing; | |
444 } else { | |
445 imageY = topMargin; | |
446 } | |
447 | |
448 paint.drawImage(x + (boxWidth - image.width())/2, | |
449 imageY, | |
450 image); | |
451 | |
452 if (additionalText != "") { | |
453 paint.drawText(x, | |
454 imageY + image.height() + paint.fontMetrics().ascent(), | |
455 additionalText); | |
456 paint.restore(); | |
457 } | |
458 | |
459 if (label != "") { | |
460 paint.drawLine(x, | |
461 topMargin + labelRect.height() + spacing, | |
462 x + boxWidth, | |
463 topMargin + labelRect.height() + spacing); | |
464 | |
465 paint.drawText(QRect(x, | |
466 topMargin, | |
467 boxWidth, | |
468 labelRect.height()), | |
469 Qt::AlignCenter | Qt::TextWordWrap, | |
470 label); | |
471 } | |
373 } | 472 } |
374 | 473 |
375 void | 474 void |
376 ImageLayer::setLayerDormant(const View *v, bool dormant) | 475 ImageLayer::setLayerDormant(const View *v, bool dormant) |
377 { | 476 { |
387 } | 486 } |
388 } | 487 } |
389 | 488 |
390 //!!! how to reap no-longer-used images? | 489 //!!! how to reap no-longer-used images? |
391 | 490 |
392 float | 491 bool |
393 ImageLayer::getImageAspect(QString name) const | 492 ImageLayer::getImageOriginalSize(QString name, QSize &size) const |
394 { | 493 { |
395 if (m_images.find(name) == m_images.end()) { | 494 if (m_images.find(name) == m_images.end()) { |
396 m_images[name] = QImage(name); | 495 m_images[name] = QImage(name); |
397 } | 496 } |
398 if (m_images[name].isNull()) return 1.f; | 497 if (m_images[name].isNull()) { |
399 return float(m_images[name].width()) / float(m_images[name].height()); | 498 return false; |
499 } else { | |
500 size = m_images[name].size(); | |
501 return true; | |
502 } | |
400 } | 503 } |
401 | 504 |
402 QImage | 505 QImage |
403 ImageLayer::getImage(View *v, QString name, QSize maxSize) const | 506 ImageLayer::getImage(View *v, QString name, QSize maxSize) const |
404 { | 507 { |
405 bool need = false; | 508 bool need = false; |
406 | 509 |
407 // std::cerr << "ImageLayer::getImage(" << v << ", " << name.toStdString() << ", (" | 510 std::cerr << "ImageLayer::getImage(" << v << ", " << name.toStdString() << ", (" |
408 // << maxSize.width() << "x" << maxSize.height() << "))" << std::endl; | 511 << maxSize.width() << "x" << maxSize.height() << "))" << std::endl; |
409 | 512 |
410 if (!m_scaled[v][name].isNull() && | 513 if (!m_scaled[v][name].isNull() && |
411 (m_scaled[v][name].width() == maxSize.width() || | 514 ((m_scaled[v][name].width() == maxSize.width() && |
412 m_scaled[v][name].height() == maxSize.height())) { | 515 m_scaled[v][name].height() <= maxSize.height()) || |
413 // std::cerr << "cache hit" << std::endl; | 516 (m_scaled[v][name].width() <= maxSize.width() && |
517 m_scaled[v][name].height() == maxSize.height()))) { | |
518 std::cerr << "cache hit" << std::endl; | |
414 return m_scaled[v][name]; | 519 return m_scaled[v][name]; |
415 } | 520 } |
416 | 521 |
417 if (m_images.find(name) == m_images.end()) { | 522 if (m_images.find(name) == m_images.end()) { |
418 m_images[name] = QImage(name); | 523 m_images[name] = QImage(name); |
419 } | 524 } |
420 | 525 |
421 if (m_images[name].isNull()) { | 526 if (m_images[name].isNull()) { |
422 // std::cerr << "null image" << std::endl; | 527 std::cerr << "null image" << std::endl; |
423 m_scaled[v][name] = QImage(); | 528 m_scaled[v][name] = QImage(); |
529 } else if (m_images[name].width() <= maxSize.width() && | |
530 m_images[name].height() <= maxSize.height()) { | |
531 m_scaled[v][name] = m_images[name]; | |
424 } else { | 532 } else { |
425 m_scaled[v][name] = | 533 m_scaled[v][name] = |
426 m_images[name].scaled(maxSize, | 534 m_images[name].scaled(maxSize, |
427 Qt::KeepAspectRatio, | 535 Qt::KeepAspectRatio, |
428 Qt::SmoothTransformation); | 536 Qt::SmoothTransformation); |