changeset 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
files layer/ImageLayer.cpp layer/ImageLayer.h widgets/ImageDialog.cpp widgets/ImageDialog.h
diffstat 4 files changed, 220 insertions(+), 93 deletions(-) [+]
line wrap: on
line diff
--- a/layer/ImageLayer.cpp	Thu Oct 04 16:34:11 2007 +0000
+++ b/layer/ImageLayer.cpp	Fri Oct 05 13:27:21 2007 +0000
@@ -110,8 +110,7 @@
 bool
 ImageLayer::isLayerScrollable(const View *v) const
 {
-    QPoint discard;
-    return !v->shouldIlluminateLocalFeatures(this, discard);
+    return true;
 }
 
 
@@ -120,31 +119,43 @@
 {
     if (!m_model) return ImageModel::PointList();
 
-    std::cerr << "ImageLayer::getLocalPoints(" << x << "," << y << "):";
-
-    long frame0 = v->getFrameForX(-150);
-    long frame1 = v->getFrameForX(v->width() + 150);
-    
-    ImageModel::PointList points(m_model->getPoints(frame0, frame1));
+//    std::cerr << "ImageLayer::getLocalPoints(" << x << "," << y << "):";
+    const ImageModel::PointList &points(m_model->getPoints());
 
     ImageModel::PointList rv;
 
-    //!!! need to store drawn size as well as original size for each
-    //image, but for now:
-
-    for (ImageModel::PointList::iterator i = points.begin();
-	 i != points.end(); ++i) {
+    for (ImageModel::PointList::const_iterator i = points.begin();
+	 i != points.end(); ) {
 
 	const ImageModel::Point &p(*i);
+	int px = v->getXForFrame(p.frame);
+        if (px > x) break;
 
-	int px = v->getXForFrame(p.frame);
+        ++i;
+        if (i != points.end()) {
+            int nx = v->getXForFrame((*i).frame);
+            if (nx < x) {
+                // as we aim not to overlap the images, if the following
+                // image begins to the left of a point then the current
+                // one may be assumed to end to the left of it as well.
+                continue;
+            }
+        }
 
-        if (x >= px && x < px + 100) {
+        // this image is a candidate, test it properly
+
+        int width = 32;
+        if (m_scaled[v].find(p.image) != m_scaled[v].end()) {
+            width = m_scaled[v][p.image].width();
+            std::cerr << "scaled width = " << width << std::endl;
+        }
+
+        if (x >= px && x < px + width) {
             rv.insert(p);
         }
     }
 
-    std::cerr << rv.size() << " point(s)" << std::endl;
+//    std::cerr << rv.size() << " point(s)" << std::endl;
 
     return rv;
 }
@@ -270,31 +281,32 @@
 
 //    Profiler profiler("ImageLayer::paint", true);
 
-    int x0 = rect.left(), x1 = rect.right();
+//    int x0 = rect.left(), x1 = rect.right();
+    int x0 = 0, x1 = v->width();
+
     long frame0 = v->getFrameForX(x0);
     long frame1 = v->getFrameForX(x1);
 
     ImageModel::PointList points(m_model->getPoints(frame0, frame1));
     if (points.empty()) return;
 
+    paint.save();
+    paint.setClipRect(rect.x(), 0, rect.width(), v->height());
+
     QColor penColour;
     penColour = v->getForeground();
 
-//    std::cerr << "ImageLayer::paint: resolution is "
-//	      << m_model->getResolution() << " frames" << std::endl;
+    QColor brushColour;
+    brushColour = v->getBackground();
 
-    QPoint localPos;
-    long illuminateFrame = -1;
+    int h, s, val;
+    brushColour.getHsv(&h, &s, &val);
+    brushColour.setHsv(h, s, 255, 240);
 
-    if (v->shouldIlluminateLocalFeatures(this, localPos)) {
-	ImageModel::PointList localPoints = getLocalPoints(v, localPos.x(),
-							  localPos.y());
-	if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
-    }
+    paint.setPen(penColour);
+    paint.setBrush(brushColour);
+    paint.setRenderHint(QPainter::Antialiasing, true);
 
-    paint.save();
-    paint.setClipRect(rect.x(), 0, rect.width(), v->height());
-    
     for (ImageModel::PointList::const_iterator i = points.begin();
 	 i != points.end(); ++i) {
 
@@ -309,67 +321,154 @@
             int jx = v->getXForFrame(j->frame);
             if (jx < nx) nx = jx;
         }
-/*
-	if (illuminateFrame == p.frame) {
-	    paint.setBrush(penColour);
-            paint.setPen(v->getBackground());
-	} else {
-	    paint.setPen(penColour);
-	    paint.setBrush(brushColour);
-	}
-*/
-	QString label = p.label;
-        QString imageName = p.image;
 
-        int nw = nx - x;
-        if (nw < 10) nw = 20;
+        drawImage(v, paint, p, x, nx);
+    }
 
-        int top = 10;
-        if (v->height() < 50) top = 5;
-        
-        int bottom = top;
+    paint.setRenderHint(QPainter::Antialiasing, false);
+    paint.restore();
+}
 
-        QRect labelRect;
-        if (label != "") {
-            float aspect = getImageAspect(imageName);
-            int iw = lrintf((v->height() - v->height()/4 - top - bottom)
-                            * aspect);
-            labelRect = paint.fontMetrics().boundingRect
-                (QRect(0, 0, iw, v->height()/4),
-                 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, label);
-            bottom += labelRect.height() + 5;
+void
+ImageLayer::drawImage(View *v, QPainter &paint, const ImageModel::Point &p,
+                      int x, int nx) const
+{
+    QString label = p.label;
+    QString imageName = p.image;
+
+    QImage image;
+    QString additionalText;
+
+    QSize imageSize;
+    if (!getImageOriginalSize(imageName, imageSize)) {
+        image = QImage(":icons/emptypage.png");
+        imageSize = image.size();
+        additionalText = imageName;
+    }
+
+    int topMargin = 10;
+    int bottomMargin = 10;
+    int spacing = 5;
+
+    if (v->height() < 100) {
+        topMargin = 5;
+        bottomMargin = 5;
+    }
+
+    int maxBoxHeight = v->height() - topMargin - bottomMargin;
+
+    int availableWidth = nx - x - 3;
+    if (availableWidth < 20) availableWidth = 20;
+
+    QRect labelRect;
+
+    if (label != "") {
+
+        int likelyHeight = v->height() / 4;
+
+        int likelyWidth = // available height times image aspect
+            ((maxBoxHeight - likelyHeight) * imageSize.width())
+            / imageSize.height();
+
+        if (likelyWidth > imageSize.width()) {
+            likelyWidth = imageSize.width();
         }
 
-        QImage image = getImage(v,
-                                imageName,
-                                QSize(nw, v->height() - top - bottom));
-
-        if (image.isNull()) {
-            image = QImage(":icons/emptypage.png");
+        if (likelyWidth > availableWidth) {
+            likelyWidth = availableWidth;
         }
 
-	paint.setRenderHint(QPainter::Antialiasing, false);
-
-        int boxWidth = image.width();
-
-        if (label != "") {
-            boxWidth = std::max(boxWidth, labelRect.width());
+        int singleWidth = paint.fontMetrics().width(label);
+        if (singleWidth < availableWidth && singleWidth < likelyWidth * 2) {
+            likelyWidth = singleWidth + 4;
         }
 
-	paint.drawRect(x-1, top-1, boxWidth+1, v->height() - 2 * top +1);
+        labelRect = paint.fontMetrics().boundingRect
+            (QRect(0, 0, likelyWidth, likelyHeight),
+             Qt::AlignCenter | Qt::TextWordWrap, label);
 
-        paint.setRenderHint(QPainter::Antialiasing, true);
-
-        paint.drawImage(x + (boxWidth - image.width())/2, top, image);
-
-        paint.drawText(QRect(x, v->height() - bottom + 5,
-                             boxWidth, labelRect.height()),
-                       Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
-		       label);
+        labelRect.setWidth(labelRect.width() + 6);
     }
 
-    paint.restore();
-    paint.setRenderHint(QPainter::Antialiasing, false);
+    if (image.isNull()) {
+        image = getImage(v, imageName,
+                         QSize(availableWidth,
+                               maxBoxHeight - labelRect.height()));
+    }
+
+    int boxWidth = image.width();
+    if (boxWidth < labelRect.width()) {
+        boxWidth = labelRect.width();
+    }
+
+    int boxHeight = image.height();
+    if (label != "") {
+        boxHeight += labelRect.height() + spacing;
+    }
+
+    int division = image.height();
+
+    if (additionalText != "") {
+
+        paint.save();
+
+        QFont font(paint.font());
+        font.setItalic(true);
+        paint.setFont(font);
+
+        int tw = paint.fontMetrics().width(additionalText);
+        if (tw > availableWidth) {
+            tw = availableWidth;
+        }
+        if (boxWidth < tw) {
+            boxWidth = tw;
+        }
+        boxHeight += paint.fontMetrics().height();
+        division += paint.fontMetrics().height();
+    }                
+
+    bottomMargin = v->height() - topMargin - boxHeight;
+    if (bottomMargin > topMargin + v->height()/7) {
+        topMargin += v->height()/8;
+        bottomMargin -= v->height()/8;
+    }
+
+    paint.drawRect(x - 1,
+                   topMargin - 1,
+                   boxWidth + 2,
+                   boxHeight + 2);
+
+    int imageY;
+    if (label != "") {
+        imageY = topMargin + labelRect.height() + spacing;
+    } else {
+        imageY = topMargin;
+    }
+
+    paint.drawImage(x + (boxWidth - image.width())/2,
+                    imageY,
+                    image);
+
+    if (additionalText != "") {
+        paint.drawText(x,
+                       imageY + image.height() + paint.fontMetrics().ascent(),
+                       additionalText);
+        paint.restore();
+    }
+
+    if (label != "") {
+        paint.drawLine(x,
+                       topMargin + labelRect.height() + spacing,
+                       x + boxWidth, 
+                       topMargin + labelRect.height() + spacing);
+
+        paint.drawText(QRect(x,
+                             topMargin,
+                             boxWidth,
+                             labelRect.height()),
+                       Qt::AlignCenter | Qt::TextWordWrap,
+                       label);
+    }
 }
 
 void
@@ -389,14 +488,18 @@
 
 //!!! how to reap no-longer-used images?
 
-float
-ImageLayer::getImageAspect(QString name) const
+bool
+ImageLayer::getImageOriginalSize(QString name, QSize &size) const
 {
     if (m_images.find(name) == m_images.end()) {
         m_images[name] = QImage(name);
     }
-    if (m_images[name].isNull()) return 1.f;
-    return float(m_images[name].width()) / float(m_images[name].height());
+    if (m_images[name].isNull()) {
+        return false;
+    } else {
+        size = m_images[name].size();
+        return true;
+    }
 }
 
 QImage 
@@ -404,13 +507,15 @@
 {
     bool need = false;
 
-//    std::cerr << "ImageLayer::getImage(" << v << ", " << name.toStdString() << ", ("
-//              << maxSize.width() << "x" << maxSize.height() << "))" << std::endl;
+    std::cerr << "ImageLayer::getImage(" << v << ", " << name.toStdString() << ", ("
+              << maxSize.width() << "x" << maxSize.height() << "))" << std::endl;
 
-    if (!m_scaled[v][name].isNull() &&
-        (m_scaled[v][name].width() == maxSize.width() ||
-         m_scaled[v][name].height() == maxSize.height())) {
-//        std::cerr << "cache hit" << std::endl;
+    if (!m_scaled[v][name].isNull()  &&
+        ((m_scaled[v][name].width()  == maxSize.width() &&
+          m_scaled[v][name].height() <= maxSize.height()) ||
+         (m_scaled[v][name].width()  <= maxSize.width() &&
+          m_scaled[v][name].height() == maxSize.height()))) {
+        std::cerr << "cache hit" << std::endl;
         return m_scaled[v][name];
     }
 
@@ -419,8 +524,11 @@
     }
 
     if (m_images[name].isNull()) {
-//        std::cerr << "null image" << std::endl;
+        std::cerr << "null image" << std::endl;
         m_scaled[v][name] = QImage();
+    } else if (m_images[name].width() <= maxSize.width() &&
+               m_images[name].height() <= maxSize.height()) {
+        m_scaled[v][name] = m_images[name];
     } else {
         m_scaled[v][name] =
             m_images[name].scaled(maxSize,
--- a/layer/ImageLayer.h	Thu Oct 04 16:34:11 2007 +0000
+++ b/layer/ImageLayer.h	Fri Oct 05 13:27:21 2007 +0000
@@ -96,14 +96,19 @@
 protected:
     ImageModel::PointList getLocalPoints(View *v, int x, int y) const;
 
-    float getImageAspect(QString name) const;
+    bool getImageOriginalSize(QString name, QSize &size) const;
     QImage getImage(View *v, QString name, QSize maxSize) const;
 
+    void drawImage(View *v, QPainter &paint, const ImageModel::Point &p,
+                   int x, int nx) const;
+
     //!!! how to reap no-longer-used images?
 
     typedef std::map<QString, QImage> ImageMap;
     typedef std::map<const View *, ImageMap> ViewImageMap;
 
+
+
     static ImageMap m_images;
     mutable ViewImageMap m_scaled;
 
--- a/widgets/ImageDialog.cpp	Thu Oct 04 16:34:11 2007 +0000
+++ b/widgets/ImageDialog.cpp	Fri Oct 05 13:27:21 2007 +0000
@@ -21,6 +21,8 @@
 #include <QDialogButtonBox>
 #include <QPushButton>
 #include <QGroupBox>
+#include <QDesktopWidget>
+#include <QApplication>
 
 #include "data/fileio/FileFinder.h"
 
@@ -53,8 +55,9 @@
     subgrid->addWidget(new QLabel(tr("File:")), row, 0);
 
     m_imageEdit = new QLineEdit;
-    m_imageEdit->setReadOnly(true);
     subgrid->addWidget(m_imageEdit, row, 1, 1, 1);
+    connect(m_imageEdit, SIGNAL(textEdited(const QString &)),
+            this, SLOT(imageEditEdited(const QString &)));
 
     QPushButton *browse = new QPushButton(tr("Browse..."));
     connect(browse, SIGNAL(clicked()), this, SLOT(browseClicked()));
@@ -73,6 +76,10 @@
 
     m_imagePreview->setMinimumSize(QSize(100, 100));
 
+    QDesktopWidget *desktop = QApplication::desktop();
+    m_imagePreview->setMaximumSize(QSize((desktop->width() * 2) / 3,
+                                         (desktop->height() * 2) / 3));
+
     grid->addWidget(databox, 0, 0);
     grid->addWidget(previewbox, 1, 0);
 
@@ -133,12 +140,20 @@
 }
 
 void
+ImageDialog::imageEditEdited(const QString &)
+{
+    updatePreview();
+}
+
+void
 ImageDialog::updatePreview()
 {
     if (!m_imagePreview) return;
 
     QString img = m_imageEdit->text();
 
+    m_okButton->setEnabled(img != "");
+
     if (img != m_loadedImageFile) {
         m_loadedImage = QPixmap(img);
         m_loadedImageFile = img;
@@ -150,13 +165,11 @@
 
     if (m_loadedImage.isNull()) {
         m_imagePreview->setPixmap(QPixmap());
-        m_okButton->setEnabled(false);
     } else {
         m_imagePreview->setPixmap(m_loadedImage.scaled
                                   (sz,
                                    Qt::KeepAspectRatio,
                                    Qt::SmoothTransformation));
-        m_okButton->setEnabled(true);
     }
 }
 
--- a/widgets/ImageDialog.h	Thu Oct 04 16:34:11 2007 +0000
+++ b/widgets/ImageDialog.h	Fri Oct 05 13:27:21 2007 +0000
@@ -49,6 +49,7 @@
 
 protected slots:
     void browseClicked();
+    void imageEditEdited(const QString &);
 
 protected:
     void resizeEvent(QResizeEvent *);