Commit aecc390d authored by Arjen Hiemstra's avatar Arjen Hiemstra Committed by Nate Graham
Browse files

Extract background painting into its own custom QGraphicsItem

Rather than duplicating the background code everywhere, we can move it
to its own QGraphicsItem which takes care of painting the right
background.
parent 3173858c
......@@ -90,6 +90,7 @@ set(gwenviewlib_SRCS
documentview/abstractdocumentviewadapter.cpp
documentview/abstractimageview.cpp
documentview/abstractrasterimageviewtool.cpp
documentview/alphabackgrounditem.cpp
documentview/birdeyeview.cpp
documentview/documentview.cpp
documentview/documentviewcontroller.cpp
......
......@@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA
// Local
#include "gwenview_lib_debug.h"
#include "alphabackgrounditem.h"
// KF
......@@ -60,7 +61,7 @@ struct AbstractImageViewPrivate
QPointF mLastDragPos;
QSizeF mDocumentSize;
const QPixmap mAlphaBackgroundTexture;
AlphaBackgroundItem* mBackgroundItem;
void adjustImageOffset(Verbosity verbosity = Notify)
{
......@@ -70,8 +71,11 @@ struct AbstractImageViewPrivate
qMax((viewSize.width() - zoomedDocSize.width()) / 2, qreal(0.)),
qMax((viewSize.height() - zoomedDocSize.height()) / 2, qreal(0.))
);
if (offset != mImageOffset) {
mImageOffset = offset;
if (verbosity == Notify) {
q->onImageOffsetChanged();
}
......@@ -98,6 +102,8 @@ struct AbstractImageViewPrivate
if (newPos != mScrollPos) {
QPointF oldPos = mScrollPos;
mScrollPos = newPos;
if (verbosity == Notify) {
q->onScrollPosChanged(oldPos);
}
......@@ -116,23 +122,13 @@ struct AbstractImageViewPrivate
mZoomCursor = QCursor(cursorPixmap, 11, 11);
}
QPixmap createAlphaBackgroundTexture()
AbstractImageViewPrivate(AbstractImageView *parent)
: q(parent)
, mBackgroundItem(new AlphaBackgroundItem{q})
{
QPixmap pix = QPixmap(32, 32);
QPainter painter(&pix);
painter.fillRect(pix.rect(), QColor(128, 128, 128));
const QColor light = QColor(192, 192, 192);
painter.fillRect(0, 0, 16, 16, light);
painter.fillRect(16, 16, 16, 16, light);
pix.setDevicePixelRatio(q->devicePixelRatio());
return pix;
mBackgroundItem->setVisible(false);
}
AbstractImageViewPrivate(AbstractImageView *parent) :
q(parent),
mAlphaBackgroundTexture(createAlphaBackgroundTexture())
{ }
void checkAndRequestZoomAction(const QGraphicsSceneMouseEvent* event)
{
if (event->modifiers() & Qt::ControlModifier) {
......@@ -183,6 +179,10 @@ void AbstractImageView::setDocument(const Document::Ptr &doc)
disconnect(d->mDocument.data(), nullptr, this, nullptr);
}
d->mDocument = doc;
if (d->mDocument) {
connect(d->mDocument.data(), &Document::imageRectUpdated, this, &AbstractImageView::onImageRectUpdated);
}
loadFromDocument();
}
......@@ -301,11 +301,6 @@ void AbstractImageView::setZoomToFill(bool on, const QPointF& center)
emit zoomToFillChanged(d->mZoomToFill);
}
const QPixmap& AbstractImageView::alphaBackgroundTexture() const
{
return d->mAlphaBackgroundTexture;
}
void AbstractImageView::resizeEvent(QGraphicsSceneResizeEvent* event)
{
QGraphicsWidget::resizeEvent(event);
......@@ -633,4 +628,22 @@ void AbstractImageView::resetDragCursor()
updateCursor();
}
AlphaBackgroundItem* AbstractImageView::backgroundItem() const
{
return d->mBackgroundItem;
}
void AbstractImageView::onImageRectUpdated()
{
if (zoomToFit()) {
setZoom(computeZoomToFit());
} else if (zoomToFill()) {
setZoom(computeZoomToFill());
} else {
applyPendingScrollPos();
}
update();
}
} // namespace
......@@ -32,6 +32,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA
namespace Gwenview
{
class AlphaBackgroundItem;
struct AbstractImageViewPrivate;
/**
*
......@@ -119,6 +121,8 @@ public:
void resetDragCursor();
AlphaBackgroundItem* backgroundItem() const;
public Q_SLOTS:
void updateCursor();
......@@ -135,10 +139,6 @@ Q_SIGNALS:
void toggleFullScreenRequested();
protected:
virtual void setAlphaBackgroundMode(AlphaBackgroundMode mode) = 0;
virtual void setAlphaBackgroundColor(const QColor& color) = 0;
const QPixmap& alphaBackgroundTexture() const;
virtual void loadFromDocument() = 0;
virtual void onZoomChanged() = 0;
/**
......@@ -152,6 +152,8 @@ protected:
*/
virtual void onScrollPosChanged(const QPointF& oldPos) = 0;
void onImageRectUpdated();
void resizeEvent(QGraphicsSceneResizeEvent* event) override;
void focusInEvent(QFocusEvent* event) override;
......
/*
* SPDX-FileCopyrightText: 2021 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "alphabackgrounditem.h"
#include <QApplication>
#include <QPainter>
using namespace Gwenview;
AlphaBackgroundItem::AlphaBackgroundItem(AbstractImageView* parent)
: QGraphicsItem(parent)
, mParent(parent)
{
}
AlphaBackgroundItem::~AlphaBackgroundItem()
{
}
AbstractImageView::AlphaBackgroundMode AlphaBackgroundItem::mode() const
{
return mMode;
}
void Gwenview::AlphaBackgroundItem::setMode(AbstractImageView::AlphaBackgroundMode mode)
{
if (mode == mMode) {
return;
}
mMode = mode;
update();
}
QColor AlphaBackgroundItem::color()
{
return mColor;
}
void AlphaBackgroundItem::setColor(const QColor& color)
{
if (color == mColor) {
return;
}
mColor = color;
update();
}
void AlphaBackgroundItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
{
// We need to floor the image size. Unfortunately, QPointF and QSizeF both
// _round_ when converting instead of flooring. This means that we need to
// manually do the flooring here, because we otherwise run into pixel
// alignment issues with the image that is drawn on top of the background.
const auto width = int((mParent->documentSize().width() / qApp->devicePixelRatio()) * mParent->zoom());
const auto height = int((mParent->documentSize().height() / qApp->devicePixelRatio()) * mParent->zoom());
const auto imageRect = QRectF{mParent->imageOffset().toPoint(), QSize{width, height}};
switch (mMode) {
case AbstractImageView::AlphaBackgroundNone:
// No background, do not paint anything.
break;
case AbstractImageView::AlphaBackgroundCheckBoard:
{
if (!mCheckBoardTexture) {
createCheckBoardTexture();
}
painter->drawTiledPixmap(imageRect, *mCheckBoardTexture, mParent->scrollPos());
break;
}
case AbstractImageView::AlphaBackgroundSolid:
painter->fillRect(imageRect, mColor);
break;
default:
break;
}
}
QRectF AlphaBackgroundItem::boundingRect() const
{
return mParent->boundingRect();
}
void AlphaBackgroundItem::createCheckBoardTexture()
{
mCheckBoardTexture = std::make_unique<QPixmap>(32, 32);
QPainter painter(mCheckBoardTexture.get());
painter.fillRect(mCheckBoardTexture->rect(), QColor(128, 128, 128));
const QColor light = QColor(192, 192, 192);
painter.fillRect(0, 0, 16, 16, light);
painter.fillRect(16, 16, 16, 16, light);
// Don't set the pixmap's devicePixelRatio, just let Qt take care of scaling
// this, otherwise we get some ugly glitches.
}
/*
* SPDX-FileCopyrightText: 2021 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef BACKGROUNDITEM_H
#define BACKGROUNDITEM_H
#include <QGraphicsItem>
#include <lib/gwenviewlib_export.h>
#include "abstractimageview.h"
namespace Gwenview
{
/**
* A QGraphicsItem subclass that draws the appropriate background for alpha images.
*/
class GWENVIEWLIB_EXPORT AlphaBackgroundItem : public QGraphicsItem
{
public:
AlphaBackgroundItem(AbstractImageView* parent);
~AlphaBackgroundItem() override;
AbstractImageView::AlphaBackgroundMode mode() const;
void setMode(AbstractImageView::AlphaBackgroundMode mode);
QColor color();
void setColor(const QColor& color);
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/) override;
virtual QRectF boundingRect() const override;
private:
void createCheckBoardTexture();
AbstractImageView* mParent;
AbstractImageView::AlphaBackgroundMode mMode = AbstractImageView::AlphaBackgroundCheckBoard;
QColor mColor = Qt::black;
// This pixmap will be used to fill the background when mMode is
// AlphaBackgroundCheckBoard.
std::unique_ptr<QPixmap> mCheckBoardTexture;
};
}
#endif // BACKGROUNDITEM_H
......@@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA
#include <lib/gvdebug.h>
#include <lib/paintutils.h>
#include "gwenview_lib_debug.h"
#include "alphabackgrounditem.h"
// KF
......@@ -121,10 +122,6 @@ struct RasterImageViewPrivate
QGraphicsItem* mImageItem;
ToolPainter* mToolItem = nullptr;
// Config
AbstractImageView::AlphaBackgroundMode mAlphaBackgroundMode = AbstractImageView::AlphaBackgroundNone;
QColor mAlphaBackgroundColor = Qt::black;
cmsUInt32Number mRenderingIntent = INTENT_PERCEPTUAL;
QPointer<AbstractRasterImageViewTool> mTool;
......@@ -132,8 +129,6 @@ struct RasterImageViewPrivate
bool mApplyDisplayTransform = true; // Can be set to false if there is no need or no way to apply color profile
cmsHTRANSFORM mDisplayTransform = nullptr;
bool mLoaded = false;
void updateDisplayTransform(QImage::Format format)
{
GV_RETURN_IF_FAIL(format != QImage::Format_Invalid);
......@@ -233,18 +228,6 @@ RasterImageView::~RasterImageView()
delete d;
}
void RasterImageView::setAlphaBackgroundMode(AlphaBackgroundMode mode)
{
d->mAlphaBackgroundMode = mode;
update();
}
void RasterImageView::setAlphaBackgroundColor(const QColor& color)
{
d->mAlphaBackgroundColor = color;
update();
}
void RasterImageView::setRenderingIntent(const RenderingIntent::Enum& renderingIntent)
{
if (d->mRenderingIntent != renderingIntent) {
......@@ -310,7 +293,7 @@ void RasterImageView::finishSetDocument()
d->startAnimationIfNecessary();
update();
d->mLoaded = true;
backgroundItem()->setVisible(true);
Q_EMIT completed();
}
......@@ -337,13 +320,6 @@ void RasterImageView::onScrollPosChanged(const QPointF& oldPos)
d->adjustItemPosition();
}
void RasterImageView::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
{
if (d->mLoaded) {
drawAlphaBackground(painter);
}
}
void RasterImageView::setCurrentTool(AbstractRasterImageViewTool* tool)
{
if (d->mTool) {
......@@ -458,24 +434,4 @@ void RasterImageView::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
AbstractImageView::hoverMoveEvent(event);
}
void RasterImageView::drawAlphaBackground(QPainter* painter)
{
const QRect imageRect = QRect(imageOffset().toPoint(), visibleImageSize().toSize());
switch (d->mAlphaBackgroundMode) {
case AbstractImageView::AlphaBackgroundNone:
break;
case AbstractImageView::AlphaBackgroundCheckBoard:
{
painter->drawTiledPixmap(imageRect, alphaBackgroundTexture(), scrollPos());
break;
}
case AbstractImageView::AlphaBackgroundSolid:
painter->fillRect(imageRect, d->mAlphaBackgroundColor);
break;
default:
Q_ASSERT(0);
}
}
} // namespace
......@@ -44,13 +44,9 @@ public:
explicit RasterImageView(QGraphicsItem* parent = nullptr);
~RasterImageView() override;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
void setCurrentTool(AbstractRasterImageViewTool* tool);
AbstractRasterImageViewTool* currentTool() const;
void setAlphaBackgroundMode(AlphaBackgroundMode mode) override;
void setAlphaBackgroundColor(const QColor& color) override;
void setRenderingIntent(const RenderingIntent::Enum& renderingIntent);
void resetMonitorICC();
......@@ -78,8 +74,6 @@ private Q_SLOTS:
void finishSetDocument();
private:
void drawAlphaBackground(QPainter* painter);
RasterImageViewPrivate* const d;
};
......
......@@ -26,6 +26,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA
#include <lib/documentview/rasterimageview.h>
#include <lib/gwenviewconfig.h>
#include "alphabackgrounditem.h"
// KF
// Qt
......@@ -136,8 +138,8 @@ void RasterImageViewAdapter::slotLoadingFailed()
void RasterImageViewAdapter::loadConfig()
{
d->mView->setAlphaBackgroundMode(GwenviewConfig::alphaBackgroundMode());
d->mView->setAlphaBackgroundColor(GwenviewConfig::alphaBackgroundColor());
d->mView->backgroundItem()->setMode(GwenviewConfig::alphaBackgroundMode());
d->mView->backgroundItem()->setColor(GwenviewConfig::alphaBackgroundColor());
d->mView->setRenderingIntent(GwenviewConfig::renderingIntent());
d->mView->setEnlargeSmallerImages(GwenviewConfig::enlargeSmallerImages());
d->mView->resetMonitorICC();
......
......@@ -36,6 +36,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA
#include "document/documentfactory.h"
#include <lib/gvdebug.h>
#include <lib/gwenviewconfig.h>
#include "alphabackgrounditem.h"
namespace Gwenview
{
......@@ -44,9 +45,6 @@ namespace Gwenview
SvgImageView::SvgImageView(QGraphicsItem* parent)
: AbstractImageView(parent)
, mSvgItem(new QGraphicsSvgItem(this))
, mAlphaBackgroundMode(AbstractImageView::AlphaBackgroundCheckBoard)
, mAlphaBackgroundColor(Qt::black)
, mImageFullyLoaded(false)
{
// At certain scales, the SVG can render outside its own bounds up to 1 pixel
// This clips it so it isn't drawn outside the background or over the selection rect
......@@ -85,7 +83,7 @@ void SvgImageView::finishLoadFromDocument()
}
applyPendingScrollPos();
emit completed();
mImageFullyLoaded = true;
backgroundItem()->setVisible(true);
}
void SvgImageView::onZoomChanged()
......@@ -110,46 +108,6 @@ void SvgImageView::adjustItemPos()
update();
}
void SvgImageView::setAlphaBackgroundMode(AbstractImageView::AlphaBackgroundMode mode)
{
mAlphaBackgroundMode = mode;
update();
}
void SvgImageView::setAlphaBackgroundColor(const QColor& color)
{
mAlphaBackgroundColor = color;
update();
}
void SvgImageView::drawAlphaBackground(QPainter* painter)
{
// The point and size must be rounded to integers independently, to keep consistency with RasterImageView
const QRect imageRect = QRect(imageOffset().toPoint(), visibleImageSize().toSize());
switch (mAlphaBackgroundMode) {
case AbstractImageView::AlphaBackgroundNone:
// Unlike RasterImageView, SVGs are rendered directly on the image view,
// therefore we can simply not draw a background
break;
case AbstractImageView::AlphaBackgroundCheckBoard:
painter->drawTiledPixmap(imageRect, alphaBackgroundTexture(), scrollPos());
break;
case AbstractImageView::AlphaBackgroundSolid:
painter->fillRect(imageRect, mAlphaBackgroundColor);
break;
default:
Q_ASSERT(0);
}
}
void SvgImageView::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
{
if (mImageFullyLoaded) {
drawAlphaBackground(painter);
}
}
//// SvgViewAdapter ////
struct SvgViewAdapterPrivate
{
......@@ -200,8 +158,8 @@ Document::Ptr SvgViewAdapter::document() const
void SvgViewAdapter::loadConfig()
{
d->mView->setAlphaBackgroundMode(GwenviewConfig::alphaBackgroundMode());
d->mView->setAlphaBackgroundColor(GwenviewConfig::alphaBackgroundColor());
d->mView->backgroundItem()->setMode(GwenviewConfig::alphaBackgroundMode());
d->mView->backgroundItem()->setColor(GwenviewConfig::alphaBackgroundColor());
d->mView->setEnlargeSmallerImages(GwenviewConfig::enlargeSmallerImages());
}
......
......@@ -42,8 +42,6 @@ class SvgImageView : public AbstractImageView
Q_OBJECT
public:
explicit SvgImageView(QGraphicsItem* parent = nullptr);
void setAlphaBackgroundMode(AlphaBackgroundMode mode) override;
void setAlphaBackgroundColor(const QColor& color) override;
protected:
void loadFromDocument() override;
......@@ -56,13 +54,7 @@ private Q_SLOTS:
private:
QGraphicsSvgItem* mSvgItem;
AbstractImageView::AlphaBackgroundMode mAlphaBackgroundMode;
QColor mAlphaBackgroundColor;
bool mImageFullyLoaded;
void adjustItemPos();
void drawAlphaBackground(QPainter* painter);
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
};
struct SvgViewAdapterPrivate;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment