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);