15.1.979. tablet_qt/widgets/aspectratiopixmap.cpp

/*
    Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
    Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

    This file is part of CamCOPS.

    CamCOPS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CamCOPS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
*/

/*
    OPTIONAL LGPL: Alternatively, this file may be used under the terms of the
    GNU Lesser General Public License version 3 as published by the Free
    Software Foundation. You should have received a copy of the GNU Lesser
    General Public License along with CamCOPS. If not, see
    <https://www.gnu.org/licenses/>.
*/

// #define DEBUG_LAYOUT
// #define DEBUG_CLICK_TIMING

#include "aspectratiopixmap.h"

#include <QDebug>
#include <QMouseEvent>
#include <QPainter>
#include <QResizeEvent>

#include "common/colourdefs.h"
#include "graphics/graphicsfunc.h"
#include "lib/sizehelpers.h"

AspectRatioPixmap::AspectRatioPixmap(QPixmap* pixmap, QWidget* parent) :
    QWidget(parent)
{
    setSizePolicy(sizehelpers::maximumFixedHFWPolicy());
    if (pixmap) {
        setPixmap(*pixmap);
    }
}

void AspectRatioPixmap::setPixmap(const QPixmap& pixmap)
{
#ifdef DEBUG_LAYOUT
    qDebug() << Q_FUNC_INFO;
#endif
    m_pixmap = pixmap;
    updateGeometry();  // maximum size may have changed
}

bool AspectRatioPixmap::hasHeightForWidth() const
{
    return true;
}

int AspectRatioPixmap::heightForWidth(const int width) const
{
#ifdef DEBUG_CLICK_TIMING
    qDebug() << Q_FUNC_INFO;
#endif
    // Step 1: calculate an answer that's right for our image's aspect ratio
    int h = m_pixmap.isNull()
        ? 0  // a bit arbitrary! width()? 0? 1?
        : static_cast<int>(
            (static_cast<qreal>(m_pixmap.height()) * width) / m_pixmap.width()
        );

    // Step 2: never give an answer that is greater than our maximum height,
    // or the framework may allocate too much space for it (and then display
    // us at our correct maximum size, but with giant gaps in the layout).
    h = qMin(h, m_pixmap.height());
    // ... height() is 0 for a null pixmap anyway; see qpixmap.cpp

#ifdef DEBUG_LAYOUT
    qDebug() << Q_FUNC_INFO << "width" << width << "-> height" << h;
#endif
    return h;
}

QSize AspectRatioPixmap::sizeHint() const
{
#ifdef DEBUG_CLICK_TIMING
    qDebug() << Q_FUNC_INFO;
#endif
    QSize hint = m_pixmap.size();
    // hint.rheight() = -1;
#ifdef DEBUG_LAYOUT
    qDebug() << Q_FUNC_INFO << "pixmap size" << m_pixmap.size() << "size hint"
             << hint;
#endif
    return hint;

    // PROBLEM with AspectRatioPixmap
    // If you have a 1920 x 1080 pixmap, then if you don't override sizeHint
    // you get something like a 640x380 default size. If you want the pixmap
    // to expand horizontally, you need to give a sizeHint.
    // However, if you give a sizeHint that's 1920 x 1080, the layout may
    // reduce the horizontal direction, but won't reduce the vertical
    // direction. Then, the *actual* image size is appropriately reduced
    // vertically by the resizeEvent() code, so you get a pixmap with
    // big top-and-bottom borders, because the displayed size is less than
    // the sizeHint.

    // Can you just return a width hint?
    // Well, you can, and that give the opposite problem - a right-hand border
    // with an image that's insufficiently sized.

    // This gets better if you enforce a size policy with
    // setHeightForWidth(true) set.

    // The problem may now be in VerticalScrollArea, having its vertical size
    // too large; not sure.
}

QSize AspectRatioPixmap::minimumSizeHint() const
{
    return QSize(0, 0);
}

void AspectRatioPixmap::mousePressEvent(QMouseEvent* event)
{
#ifdef DEBUG_CLICK_TIMING
    qDebug() << Q_FUNC_INFO;
#endif
    Q_UNUSED(event)
    emit clicked();
}

void AspectRatioPixmap::clear()
{
    // qDebug() << Q_FUNC_INFO;
    // If you set (1) a giant pixmap and then (2) a null pixmap, you can have
    // your size remain at the giant size.
    QPixmap blank(1, 1);
    blank.fill(QCOLOR_TRANSPARENT);
    setPixmap(blank);
}

void AspectRatioPixmap::paintEvent(QPaintEvent* event)
{
    Q_UNUSED(event)

    QPainter painter(this);
    const QRect cr = contentsRect();
    graphicsfunc::paintPixmapKeepingAspectRatio(painter, m_pixmap, cr, event);
}