mirror of https://github.com/cutefishos/fishui
build: remove KF5WindowSystem when build with MSVC
parent
fc7d3f5c44
commit
435ef1b8ee
@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
*
|
||||
* The box blur implementation is based on AlphaBoxBlur from Firefox.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// own
|
||||
#include "boxshadowrenderer.h"
|
||||
|
||||
// Qt
|
||||
#include <QPainter>
|
||||
#include <QtMath>
|
||||
|
||||
static inline int calculateBlurRadius(qreal stdDev)
|
||||
{
|
||||
// See https://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement
|
||||
const qreal gaussianScaleFactor = (3.0 * qSqrt(2.0 * M_PI) / 4.0) * 1.5;
|
||||
return qMax(2, qFloor(stdDev * gaussianScaleFactor + 0.5));
|
||||
}
|
||||
|
||||
static inline qreal calculateBlurStdDev(int radius)
|
||||
{
|
||||
// See https://www.w3.org/TR/css-backgrounds-3/#shadow-blur
|
||||
return radius * 0.5;
|
||||
}
|
||||
|
||||
static inline QSize calculateBlurExtent(int radius)
|
||||
{
|
||||
const int blurRadius = calculateBlurRadius(calculateBlurStdDev(radius));
|
||||
return QSize(blurRadius, blurRadius);
|
||||
}
|
||||
|
||||
struct BoxLobes
|
||||
{
|
||||
int left; ///< how many pixels sample to the left
|
||||
int right; ///< how many pixels sample to the right
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute box filter parameters.
|
||||
*
|
||||
* @param radius The blur radius.
|
||||
* @returns Parameters for three box filters.
|
||||
**/
|
||||
static QVector<BoxLobes> computeLobes(int radius)
|
||||
{
|
||||
const int blurRadius = calculateBlurRadius(calculateBlurStdDev(radius));
|
||||
const int z = blurRadius / 3;
|
||||
|
||||
int major;
|
||||
int minor;
|
||||
int final;
|
||||
|
||||
switch (blurRadius % 3) {
|
||||
case 0:
|
||||
major = z;
|
||||
minor = z;
|
||||
final = z;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
major = z + 1;
|
||||
minor = z;
|
||||
final = z;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
major = z + 1;
|
||||
minor = z;
|
||||
final = z + 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
Q_ASSERT(major + minor + final == blurRadius);
|
||||
|
||||
return {
|
||||
{major, minor},
|
||||
{minor, major},
|
||||
{final, final}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a row with a box filter.
|
||||
*
|
||||
* @param src The start of the row.
|
||||
* @param dst The destination.
|
||||
* @param width The width of the row, in pixels.
|
||||
* @param horizontalStride The number of bytes from one alpha value to the
|
||||
* next alpha value.
|
||||
* @param verticalStride The number of bytes from one row to the next row.
|
||||
* @param lobes Params of the box filter.
|
||||
* @param transposeInput Whether the input is transposed.
|
||||
* @param transposeOutput Whether the output should be transposed.
|
||||
**/
|
||||
static inline void boxBlurRowAlpha(const uint8_t *src, uint8_t *dst, int width, int horizontalStride,
|
||||
int verticalStride, const BoxLobes &lobes, bool transposeInput,
|
||||
bool transposeOutput)
|
||||
{
|
||||
const int inputStep = transposeInput ? verticalStride : horizontalStride;
|
||||
const int outputStep = transposeOutput ? verticalStride : horizontalStride;
|
||||
|
||||
const int boxSize = lobes.left + 1 + lobes.right;
|
||||
const int reciprocal = (1 << 24) / boxSize;
|
||||
|
||||
uint32_t alphaSum = (boxSize + 1) / 2;
|
||||
|
||||
const uint8_t *left = src;
|
||||
const uint8_t *right = src;
|
||||
uint8_t *out = dst;
|
||||
|
||||
const uint8_t firstValue = src[0];
|
||||
const uint8_t lastValue = src[(width - 1) * inputStep];
|
||||
|
||||
alphaSum += firstValue * lobes.left;
|
||||
|
||||
const uint8_t *initEnd = src + (boxSize - lobes.left) * inputStep;
|
||||
while (right < initEnd) {
|
||||
alphaSum += *right;
|
||||
right += inputStep;
|
||||
}
|
||||
|
||||
const uint8_t *leftEnd = src + boxSize * inputStep;
|
||||
while (right < leftEnd) {
|
||||
*out = (alphaSum * reciprocal) >> 24;
|
||||
alphaSum += *right - firstValue;
|
||||
right += inputStep;
|
||||
out += outputStep;
|
||||
}
|
||||
|
||||
const uint8_t *centerEnd = src + width * inputStep;
|
||||
while (right < centerEnd) {
|
||||
*out = (alphaSum * reciprocal) >> 24;
|
||||
alphaSum += *right - *left;
|
||||
left += inputStep;
|
||||
right += inputStep;
|
||||
out += outputStep;
|
||||
}
|
||||
|
||||
const uint8_t *rightEnd = dst + width * outputStep;
|
||||
while (out < rightEnd) {
|
||||
*out = (alphaSum * reciprocal) >> 24;
|
||||
alphaSum += lastValue - *left;
|
||||
left += inputStep;
|
||||
out += outputStep;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blur the alpha channel of a given image.
|
||||
*
|
||||
* @param image The input image.
|
||||
* @param radius The blur radius.
|
||||
* @param rect Specifies what part of the image to blur. If nothing is provided, then
|
||||
* the whole alpha channel of the input image will be blurred.
|
||||
**/
|
||||
static inline void boxBlurAlpha(QImage &image, int radius, const QRect &rect = {})
|
||||
{
|
||||
if (radius < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QVector<BoxLobes> lobes = computeLobes(radius);
|
||||
|
||||
const QRect blurRect = rect.isNull() ? image.rect() : rect;
|
||||
|
||||
const int alphaOffset = QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3;
|
||||
const int width = blurRect.width();
|
||||
const int height = blurRect.height();
|
||||
const int rowStride = image.bytesPerLine();
|
||||
const int pixelStride = image.depth() >> 3;
|
||||
|
||||
const int bufferStride = qMax(width, height) * pixelStride;
|
||||
QScopedPointer<uint8_t, QScopedPointerArrayDeleter<uint8_t> > buf(new uint8_t[2 * bufferStride]);
|
||||
uint8_t *buf1 = buf.data();
|
||||
uint8_t *buf2 = buf1 + bufferStride;
|
||||
|
||||
// Blur the image in horizontal direction.
|
||||
for (int i = 0; i < height; ++i) {
|
||||
uint8_t *row = image.scanLine(blurRect.y() + i) + blurRect.x() * pixelStride + alphaOffset;
|
||||
boxBlurRowAlpha(row, buf1, width, pixelStride, rowStride, lobes[0], false, false);
|
||||
boxBlurRowAlpha(buf1, buf2, width, pixelStride, rowStride, lobes[1], false, false);
|
||||
boxBlurRowAlpha(buf2, row, width, pixelStride, rowStride, lobes[2], false, false);
|
||||
}
|
||||
|
||||
// Blur the image in vertical direction.
|
||||
for (int i = 0; i < width; ++i) {
|
||||
uint8_t *column = image.scanLine(blurRect.y()) + (blurRect.x() + i) * pixelStride + alphaOffset;
|
||||
boxBlurRowAlpha(column, buf1, height, pixelStride, rowStride, lobes[0], true, false);
|
||||
boxBlurRowAlpha(buf1, buf2, height, pixelStride, rowStride, lobes[1], false, false);
|
||||
boxBlurRowAlpha(buf2, column, height, pixelStride, rowStride, lobes[2], false, true);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void mirrorTopLeftQuadrant(QImage &image)
|
||||
{
|
||||
const int width = image.width();
|
||||
const int height = image.height();
|
||||
|
||||
const int centerX = qCeil(width * 0.5);
|
||||
const int centerY = qCeil(height * 0.5);
|
||||
|
||||
const int alphaOffset = QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3;
|
||||
const int stride = image.depth() >> 3;
|
||||
|
||||
for (int y = 0; y < centerY; ++y) {
|
||||
uint8_t *in = image.scanLine(y) + alphaOffset;
|
||||
uint8_t *out = in + (width - 1) * stride;
|
||||
|
||||
for (int x = 0; x < centerX; ++x, in += stride, out -= stride) {
|
||||
*out = *in;
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < centerY; ++y) {
|
||||
const uint8_t *in = image.scanLine(y) + alphaOffset;
|
||||
uint8_t *out = image.scanLine(width - y - 1) + alphaOffset;
|
||||
|
||||
for (int x = 0; x < width; ++x, in += stride, out += stride) {
|
||||
*out = *in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void renderShadow(QPainter *painter, const QRect &rect, qreal borderRadius, const QPoint &offset, int radius, const QColor &color)
|
||||
{
|
||||
const QSize inflation = calculateBlurExtent(radius);
|
||||
const QSize size = rect.size() + 2 * inflation;
|
||||
|
||||
const qreal dpr = painter->device()->devicePixelRatioF();
|
||||
|
||||
QImage shadow(size * dpr, QImage::Format_ARGB32_Premultiplied);
|
||||
shadow.setDevicePixelRatio(dpr);
|
||||
shadow.fill(Qt::transparent);
|
||||
|
||||
QRect boxRect(QPoint(0, 0), rect.size());
|
||||
boxRect.moveCenter(QRect(QPoint(0, 0), size).center());
|
||||
|
||||
const qreal xRadius = 2.0 * borderRadius / boxRect.width();
|
||||
const qreal yRadius = 2.0 * borderRadius / boxRect.height();
|
||||
|
||||
QPainter shadowPainter;
|
||||
shadowPainter.begin(&shadow);
|
||||
shadowPainter.setRenderHint(QPainter::Antialiasing);
|
||||
shadowPainter.setPen(Qt::NoPen);
|
||||
shadowPainter.setBrush(Qt::black);
|
||||
shadowPainter.drawRoundedRect(boxRect, xRadius, yRadius);
|
||||
shadowPainter.end();
|
||||
|
||||
// Because the shadow texture is symmetrical, that's enough to blur
|
||||
// only the top-left quadrant and then mirror it.
|
||||
const QRect blurRect(0, 0, qCeil(shadow.width() * 0.5), qCeil(shadow.height() * 0.5));
|
||||
const int scaledRadius = qRound(radius * dpr);
|
||||
boxBlurAlpha(shadow, scaledRadius, blurRect);
|
||||
mirrorTopLeftQuadrant(shadow);
|
||||
|
||||
// Give the shadow a tint of the desired color.
|
||||
shadowPainter.begin(&shadow);
|
||||
shadowPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
||||
shadowPainter.fillRect(shadow.rect(), color);
|
||||
shadowPainter.end();
|
||||
|
||||
// Actually, present the shadow.
|
||||
QRect shadowRect = shadow.rect();
|
||||
shadowRect.setSize(shadowRect.size() / dpr);
|
||||
shadowRect.moveCenter(rect.center() + offset);
|
||||
painter->drawImage(shadowRect, shadow);
|
||||
}
|
||||
|
||||
void BoxShadowRenderer::setBoxSize(const QSize &size)
|
||||
{
|
||||
m_boxSize = size;
|
||||
}
|
||||
|
||||
void BoxShadowRenderer::setBorderRadius(qreal radius)
|
||||
{
|
||||
m_borderRadius = radius;
|
||||
}
|
||||
|
||||
void BoxShadowRenderer::setDevicePixelRatio(qreal dpr)
|
||||
{
|
||||
m_dpr = dpr;
|
||||
}
|
||||
|
||||
void BoxShadowRenderer::addShadow(const QPoint &offset, int radius, const QColor &color)
|
||||
{
|
||||
Shadow shadow = {};
|
||||
shadow.offset = offset;
|
||||
shadow.radius = radius;
|
||||
shadow.color = color;
|
||||
m_shadows.append(shadow);
|
||||
}
|
||||
|
||||
QImage BoxShadowRenderer::render() const
|
||||
{
|
||||
if (m_shadows.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QSize canvasSize;
|
||||
for (const Shadow &shadow : qAsConst(m_shadows)) {
|
||||
canvasSize = canvasSize.expandedTo(
|
||||
calculateMinimumShadowTextureSize(m_boxSize, shadow.radius, shadow.offset));
|
||||
}
|
||||
|
||||
QImage canvas(canvasSize * m_dpr, QImage::Format_ARGB32_Premultiplied);
|
||||
canvas.setDevicePixelRatio(m_dpr);
|
||||
canvas.fill(Qt::transparent);
|
||||
|
||||
QRect boxRect(QPoint(0, 0), m_boxSize);
|
||||
boxRect.moveCenter(QRect(QPoint(0, 0), canvasSize).center());
|
||||
|
||||
QPainter painter(&canvas);
|
||||
for (const Shadow &shadow : qAsConst(m_shadows)) {
|
||||
renderShadow(&painter, boxRect, m_borderRadius, shadow.offset, shadow.radius, shadow.color);
|
||||
}
|
||||
painter.end();
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
QSize BoxShadowRenderer::calculateMinimumBoxSize(int radius)
|
||||
{
|
||||
const QSize blurExtent = calculateBlurExtent(radius);
|
||||
return 2 * blurExtent + QSize(1, 1);
|
||||
}
|
||||
|
||||
QSize BoxShadowRenderer::calculateMinimumShadowTextureSize(const QSize &boxSize, int radius, const QPoint &offset)
|
||||
{
|
||||
return boxSize + 2 * calculateBlurExtent(radius) + QSize(qAbs(offset.x()), qAbs(offset.y()));
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Qt
|
||||
#include <QColor>
|
||||
#include <QImage>
|
||||
#include <QPoint>
|
||||
#include <QSize>
|
||||
|
||||
class BoxShadowRenderer
|
||||
{
|
||||
public:
|
||||
// Compiler generated constructors & destructor are fine.
|
||||
|
||||
/**
|
||||
* Set the size of the box.
|
||||
* @param size The size of the box.
|
||||
**/
|
||||
void setBoxSize(const QSize &size);
|
||||
|
||||
/**
|
||||
* Set the radius of box' corners.
|
||||
* @param radius The border radius, in pixels.
|
||||
**/
|
||||
void setBorderRadius(qreal radius);
|
||||
|
||||
/**
|
||||
* Set the device pixel ratio of the resulting shadow texture.
|
||||
* @param dpr The device pixel ratio.
|
||||
**/
|
||||
void setDevicePixelRatio(qreal dpr);
|
||||
|
||||
/**
|
||||
* Add a shadow.
|
||||
* @param offset The offset of the shadow.
|
||||
* @param radius The blur radius.
|
||||
* @param color The color of the shadow.
|
||||
**/
|
||||
void addShadow(const QPoint &offset, int radius, const QColor &color);
|
||||
|
||||
/**
|
||||
* Render the shadow.
|
||||
**/
|
||||
QImage render() const;
|
||||
|
||||
/**
|
||||
* Calculate the minimum size of the box.
|
||||
*
|
||||
* This helper computes the minimum size of the box so the shadow behind it has
|
||||
* full its strength.
|
||||
*
|
||||
* @param radius The blur radius of the shadow.
|
||||
**/
|
||||
static QSize calculateMinimumBoxSize(int radius);
|
||||
|
||||
/**
|
||||
* Calculate the minimum size of the shadow texture.
|
||||
*
|
||||
* This helper computes the minimum size of the resulting texture so the shadow
|
||||
* is not clipped.
|
||||
*
|
||||
* @param boxSize The size of the box.
|
||||
* @param radius The blur radius.
|
||||
* @param offset The offset of the shadow.
|
||||
**/
|
||||
static QSize calculateMinimumShadowTextureSize(const QSize &boxSize, int radius, const QPoint &offset);
|
||||
|
||||
private:
|
||||
QSize m_boxSize;
|
||||
qreal m_borderRadius = 0.0;
|
||||
qreal m_dpr = 1.0;
|
||||
|
||||
struct Shadow {
|
||||
QPoint offset;
|
||||
int radius;
|
||||
QColor color;
|
||||
};
|
||||
|
||||
QVector<Shadow> m_shadows;
|
||||
};
|
||||
@ -0,0 +1,183 @@
|
||||
/*************************************************************************
|
||||
* Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr> *
|
||||
* *
|
||||
* This program 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 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
||||
*************************************************************************/
|
||||
|
||||
#include "tileset.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
//___________________________________________________________
|
||||
inline bool bits(TileSet::Tiles flags, TileSet::Tiles testFlags)
|
||||
{ return (flags & testFlags) == testFlags; }
|
||||
|
||||
//______________________________________________________________________________________
|
||||
inline qreal devicePixelRatio( const QPixmap& pixmap )
|
||||
{
|
||||
return pixmap.devicePixelRatio();
|
||||
}
|
||||
|
||||
//______________________________________________________________________________________
|
||||
inline void setDevicePixelRatio( QPixmap& pixmap, qreal value )
|
||||
{
|
||||
return pixmap.setDevicePixelRatio( value );
|
||||
}
|
||||
|
||||
//______________________________________________________________
|
||||
void TileSet::initPixmap( PixmapList& pixmaps, const QPixmap &source, int width, int height, const QRect &rect)
|
||||
{
|
||||
QSize size( width, height );
|
||||
if( !( size.isValid() && rect.isValid() ) )
|
||||
{
|
||||
pixmaps.append( QPixmap() );
|
||||
|
||||
} else if( size != rect.size() ) {
|
||||
|
||||
const qreal dpiRatio( devicePixelRatio( source ) );
|
||||
const QRect scaledRect( rect.topLeft()*dpiRatio, rect.size()*dpiRatio );
|
||||
const QSize scaledSize( size*dpiRatio );
|
||||
const QPixmap tile( source.copy(scaledRect) );
|
||||
QPixmap pixmap( scaledSize );
|
||||
|
||||
pixmap.fill(Qt::transparent);
|
||||
QPainter painter(&pixmap);
|
||||
painter.drawTiledPixmap(0, 0, scaledSize.width(), scaledSize.height(), tile);
|
||||
setDevicePixelRatio( pixmap, dpiRatio );
|
||||
pixmaps.append( pixmap );
|
||||
|
||||
} else {
|
||||
|
||||
const qreal dpiRatio( devicePixelRatio( source ) );
|
||||
const QRect scaledRect( rect.topLeft()*dpiRatio, rect.size()*dpiRatio );
|
||||
QPixmap pixmap( source.copy( scaledRect ) );
|
||||
setDevicePixelRatio( pixmap, dpiRatio );
|
||||
pixmaps.append( pixmap );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//______________________________________________________________
|
||||
TileSet::TileSet():
|
||||
_w1(0),
|
||||
_h1(0),
|
||||
_w3(0),
|
||||
_h3(0)
|
||||
{ _pixmaps.reserve(9); }
|
||||
|
||||
//______________________________________________________________
|
||||
TileSet::TileSet(const QPixmap &source, int w1, int h1, int w2, int h2 ):
|
||||
_w1(w1),
|
||||
_h1(h1),
|
||||
_w3(0),
|
||||
_h3(0)
|
||||
{
|
||||
_pixmaps.reserve(9);
|
||||
if( source.isNull() ) return;
|
||||
|
||||
_w3 = source.width()/devicePixelRatio( source ) - (w1 + w2);
|
||||
_h3 = source.height()/devicePixelRatio( source ) - (h1 + h2);
|
||||
int w = w2;
|
||||
int h = h2;
|
||||
|
||||
// initialise pixmap array
|
||||
initPixmap( _pixmaps, source, _w1, _h1, QRect(0, 0, _w1, _h1) );
|
||||
initPixmap( _pixmaps, source, w, _h1, QRect(_w1, 0, w2, _h1) );
|
||||
initPixmap( _pixmaps, source, _w3, _h1, QRect(_w1+w2, 0, _w3, _h1) );
|
||||
initPixmap( _pixmaps, source, _w1, h, QRect(0, _h1, _w1, h2) );
|
||||
initPixmap( _pixmaps, source, w, h, QRect(_w1, _h1, w2, h2) );
|
||||
initPixmap( _pixmaps, source, _w3, h, QRect(_w1+w2, _h1, _w3, h2) );
|
||||
initPixmap( _pixmaps, source, _w1, _h3, QRect(0, _h1+h2, _w1, _h3) );
|
||||
initPixmap( _pixmaps, source, w, _h3, QRect(_w1, _h1+h2, w2, _h3) );
|
||||
initPixmap( _pixmaps, source, _w3, _h3, QRect(_w1+w2, _h1+h2, _w3, _h3) );
|
||||
}
|
||||
|
||||
//___________________________________________________________
|
||||
void TileSet::render(const QRect &constRect, QPainter *painter, Tiles tiles) const
|
||||
{
|
||||
|
||||
const bool oldHint( painter->testRenderHint( QPainter::SmoothPixmapTransform ) );
|
||||
painter->setRenderHint( QPainter::SmoothPixmapTransform, true );
|
||||
|
||||
// check initialization
|
||||
if( _pixmaps.size() < 9 ) return;
|
||||
|
||||
// copy source rect
|
||||
QRect rect( constRect );
|
||||
|
||||
// get rect dimensions
|
||||
int x0, y0, w, h;
|
||||
rect.getRect(&x0, &y0, &w, &h);
|
||||
|
||||
// calculate pixmaps widths
|
||||
int wLeft(0);
|
||||
int wRight(0);
|
||||
if( _w1+_w3 > 0 )
|
||||
{
|
||||
qreal wRatio( qreal( _w1 )/qreal( _w1 + _w3 ) );
|
||||
wLeft = (tiles&Right) ? qMin( _w1, int(w*wRatio) ):_w1;
|
||||
wRight = (tiles&Left) ? qMin( _w3, int(w*(1.0-wRatio)) ):_w3;
|
||||
}
|
||||
|
||||
// calculate pixmap heights
|
||||
int hTop(0);
|
||||
int hBottom(0);
|
||||
if( _h1+_h3 > 0 )
|
||||
{
|
||||
qreal hRatio( qreal( _h1 )/qreal( _h1 + _h3 ) );
|
||||
hTop = (tiles&Bottom) ? qMin( _h1, int(h*hRatio) ):_h1;
|
||||
hBottom = (tiles&Top) ? qMin( _h3, int(h*(1.0-hRatio)) ):_h3;
|
||||
}
|
||||
|
||||
// calculate corner locations
|
||||
w -= wLeft + wRight;
|
||||
h -= hTop + hBottom;
|
||||
const int x1 = x0 + wLeft;
|
||||
const int x2 = x1 + w;
|
||||
const int y1 = y0 + hTop;
|
||||
const int y2 = y1 + h;
|
||||
|
||||
const int w2 = _pixmaps.at(7).width()/devicePixelRatio( _pixmaps.at(7) );
|
||||
const int h2 = _pixmaps.at(5).height()/devicePixelRatio( _pixmaps.at(5) );
|
||||
|
||||
// corner
|
||||
if( bits( tiles, Top|Left) ) painter->drawPixmap(x0, y0, _pixmaps.at(0), 0, 0, wLeft*devicePixelRatio( _pixmaps.at(0) ), hTop*devicePixelRatio( _pixmaps.at(0) ));
|
||||
if( bits( tiles, Top|Right) ) painter->drawPixmap(x2, y0, _pixmaps.at(2), (_w3-wRight)*devicePixelRatio( _pixmaps.at(2) ), 0, wRight*devicePixelRatio( _pixmaps.at(2) ), hTop*devicePixelRatio( _pixmaps.at(2) ) );
|
||||
if( bits( tiles, Bottom|Left) ) painter->drawPixmap(x0, y2, _pixmaps.at(6), 0, (_h3-hBottom)*devicePixelRatio( _pixmaps.at(6) ), wLeft*devicePixelRatio( _pixmaps.at(6) ), hBottom*devicePixelRatio( _pixmaps.at(6) ));
|
||||
if( bits( tiles, Bottom|Right) ) painter->drawPixmap(x2, y2, _pixmaps.at(8), (_w3-wRight)*devicePixelRatio( _pixmaps.at(8) ), (_h3-hBottom)*devicePixelRatio( _pixmaps.at(8) ), wRight*devicePixelRatio( _pixmaps.at(8) ), hBottom*devicePixelRatio( _pixmaps.at(8) ) );
|
||||
|
||||
// top and bottom
|
||||
if( w > 0 )
|
||||
{
|
||||
if( tiles&Top ) painter->drawPixmap(x1, y0, w, hTop, _pixmaps.at(1), 0, 0, w2*devicePixelRatio( _pixmaps.at(1) ), hTop*devicePixelRatio( _pixmaps.at(1) ) );
|
||||
if( tiles&Bottom ) painter->drawPixmap(x1, y2, w, hBottom, _pixmaps.at(7), 0, (_h3-hBottom)*devicePixelRatio( _pixmaps.at(7) ), w2*devicePixelRatio( _pixmaps.at(7) ), hBottom*devicePixelRatio( _pixmaps.at(7) ) );
|
||||
}
|
||||
|
||||
// left and right
|
||||
if( h > 0 )
|
||||
{
|
||||
if( tiles&Left ) painter->drawPixmap(x0, y1, wLeft, h, _pixmaps.at(3), 0, 0, wLeft*devicePixelRatio( _pixmaps.at(3) ), h2*devicePixelRatio( _pixmaps.at(3) ) );
|
||||
if( tiles&Right ) painter->drawPixmap(x2, y1, wRight, h, _pixmaps.at(5), (_w3-wRight)*devicePixelRatio( _pixmaps.at(5) ), 0, wRight*devicePixelRatio( _pixmaps.at(5) ), h2*devicePixelRatio( _pixmaps.at(5) ) );
|
||||
}
|
||||
|
||||
// center
|
||||
if( (tiles&Center) && h > 0 && w > 0 ) painter->drawPixmap(x1, y1, w, h, _pixmaps.at(4));
|
||||
|
||||
// restore
|
||||
painter->setRenderHint( QPainter::SmoothPixmapTransform, oldHint );
|
||||
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
#ifndef TILESET_H
|
||||
#define TILESET_H
|
||||
|
||||
/*************************************************************************
|
||||
* Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr> *
|
||||
* *
|
||||
* This program 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 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QRect>
|
||||
#include <QVector>
|
||||
|
||||
//* handles proper scaling of pixmap to match widget rect.
|
||||
/**
|
||||
tilesets are collections of stretchable pixmaps corresponding to a given widget corners, sides, and center.
|
||||
corner pixmaps are never stretched. center pixmaps are
|
||||
*/
|
||||
class TileSet
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a TileSet from a pixmap. The size of the bottom/right chunks is
|
||||
whatever is left over from the other chunks, whose size is specified
|
||||
in the required parameters.
|
||||
|
||||
@param w1 width of the left chunks
|
||||
@param h1 height of the top chunks
|
||||
@param w2 width of the not-left-or-right chunks
|
||||
@param h2 height of the not-top-or-bottom chunks
|
||||
*/
|
||||
TileSet(const QPixmap&, int w1, int h1, int w2, int h2 );
|
||||
|
||||
//* empty constructor
|
||||
TileSet();
|
||||
|
||||
//* destructor
|
||||
virtual ~TileSet()
|
||||
{}
|
||||
|
||||
/**
|
||||
Flags specifying what sides to draw in ::render. Corners are drawn when
|
||||
the sides forming that corner are drawn, e.g. Top|Left draws the
|
||||
top-center, center-left, and top-left chunks. The center-center chunk is
|
||||
only drawn when Center is requested.
|
||||
*/
|
||||
enum Tile {
|
||||
Top = 0x1,
|
||||
Left = 0x2,
|
||||
Bottom = 0x4,
|
||||
Right = 0x8,
|
||||
Center = 0x10,
|
||||
TopLeft = Top|Left,
|
||||
TopRight = Top|Right,
|
||||
BottomLeft = Bottom|Left,
|
||||
BottomRight = Bottom|Right,
|
||||
Ring = Top|Left|Bottom|Right,
|
||||
Horizontal = Left|Right|Center,
|
||||
Vertical = Top|Bottom|Center,
|
||||
Full = Ring|Center
|
||||
};
|
||||
Q_DECLARE_FLAGS(Tiles, Tile)
|
||||
|
||||
/**
|
||||
Fills the specified rect with tiled chunks. Corners are never tiled,
|
||||
edges are tiled in one direction, and the center chunk is tiled in both
|
||||
directions. Partial tiles are used as needed so that the entire rect is
|
||||
perfectly filled. Filling is performed as if all chunks are being drawn.
|
||||
*/
|
||||
void render(const QRect&, QPainter*, Tiles = Ring) const;
|
||||
|
||||
//* return size associated to this tileset
|
||||
QSize size() const
|
||||
{ return QSize( _w1 + _w3, _h1 + _h3 ); }
|
||||
|
||||
//* is valid
|
||||
bool isValid() const
|
||||
{ return _pixmaps.size() == 9; }
|
||||
|
||||
//* returns pixmap for given index
|
||||
QPixmap pixmap( int index ) const
|
||||
{ return _pixmaps[index]; }
|
||||
|
||||
protected:
|
||||
|
||||
//* shortcut to pixmap list
|
||||
using PixmapList = QVector<QPixmap>;
|
||||
|
||||
//* initialize pixmap
|
||||
void initPixmap( PixmapList&, const QPixmap&, int w, int h, const QRect& );
|
||||
|
||||
private:
|
||||
|
||||
//* pixmap arry
|
||||
PixmapList _pixmaps;
|
||||
|
||||
// dimensions
|
||||
int _w1;
|
||||
int _h1;
|
||||
int _w3;
|
||||
int _h3;
|
||||
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(TileSet::Tiles)
|
||||
|
||||
#endif //TILESET_H
|
||||
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: revenmartin <revenmartin@gmail.com>
|
||||
*
|
||||
* This program 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
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "windowshadow.h"
|
||||
#include "boxshadowrenderer.h"
|
||||
#include <QDebug>
|
||||
|
||||
enum {
|
||||
ShadowNone,
|
||||
ShadowSmall,
|
||||
ShadowMedium,
|
||||
ShadowLarge,
|
||||
ShadowVeryLarge
|
||||
};
|
||||
|
||||
const CompositeShadowParams s_shadowParams[] = {
|
||||
// None
|
||||
CompositeShadowParams(),
|
||||
// Small
|
||||
CompositeShadowParams(
|
||||
QPoint(0, 3),
|
||||
ShadowParams(QPoint(0, 0), 16, 0.26),
|
||||
ShadowParams(QPoint(0, -2), 8, 0.16)),
|
||||
// Medium
|
||||
CompositeShadowParams(
|
||||
QPoint(0, 4),
|
||||
ShadowParams(QPoint(0, 0), 20, 0.24),
|
||||
ShadowParams(QPoint(0, -2), 10, 0.14)),
|
||||
// Large
|
||||
CompositeShadowParams(
|
||||
QPoint(0, 5),
|
||||
ShadowParams(QPoint(0, 0), 24, 0.22),
|
||||
ShadowParams(QPoint(0, -3), 12, 0.12)),
|
||||
// Very Large
|
||||
CompositeShadowParams(
|
||||
QPoint(0, 6),
|
||||
ShadowParams(QPoint(0, 0), 32, 0.1),
|
||||
ShadowParams(QPoint(0, -3), 16, 0.05))
|
||||
};
|
||||
|
||||
WindowShadow::WindowShadow(QObject *parent) noexcept
|
||||
: QObject(parent)
|
||||
, m_view(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
WindowShadow::~WindowShadow()
|
||||
{
|
||||
}
|
||||
|
||||
CompositeShadowParams WindowShadow::lookupShadowParams(int shadowSizeEnum)
|
||||
{
|
||||
switch (shadowSizeEnum) {
|
||||
case ShadowNone:
|
||||
return s_shadowParams[0];
|
||||
case ShadowSmall:
|
||||
return s_shadowParams[1];
|
||||
case ShadowMedium:
|
||||
return s_shadowParams[2];
|
||||
case ShadowLarge:
|
||||
return s_shadowParams[3];
|
||||
case ShadowVeryLarge:
|
||||
return s_shadowParams[4];
|
||||
default:
|
||||
// Fallback to the Large size.
|
||||
return s_shadowParams[3];
|
||||
}
|
||||
}
|
||||
|
||||
void WindowShadow::classBegin()
|
||||
{
|
||||
m_shadowTiles = this->shadowTiles();
|
||||
}
|
||||
|
||||
void WindowShadow::componentComplete()
|
||||
{
|
||||
configureTiles();
|
||||
}
|
||||
|
||||
void WindowShadow::setView(QWindow *view)
|
||||
{
|
||||
if (view != m_view) {
|
||||
m_view = view;
|
||||
emit viewChanged();
|
||||
configureTiles();
|
||||
|
||||
connect(m_view, &QWindow::visibleChanged, this, &WindowShadow::onViewVisibleChanged);
|
||||
}
|
||||
}
|
||||
|
||||
QWindow *WindowShadow::view() const
|
||||
{
|
||||
return m_view;
|
||||
}
|
||||
|
||||
void WindowShadow::setGeometry(const QRect &rect)
|
||||
{
|
||||
if (rect != m_rect) {
|
||||
m_rect = rect;
|
||||
emit geometryChanged();
|
||||
configureTiles();
|
||||
}
|
||||
}
|
||||
|
||||
QRect WindowShadow::geometry() const
|
||||
{
|
||||
return m_rect;
|
||||
}
|
||||
|
||||
void WindowShadow::setRadius(qreal value)
|
||||
{
|
||||
if (m_radius != value) {
|
||||
m_radius = value;
|
||||
emit radiusChanged();
|
||||
|
||||
this->classBegin();
|
||||
|
||||
configureTiles();
|
||||
}
|
||||
}
|
||||
|
||||
qreal WindowShadow::strength() const
|
||||
{
|
||||
return m_strength;
|
||||
}
|
||||
|
||||
void WindowShadow::setStrength(qreal strength)
|
||||
{
|
||||
if (m_strength != strength) {
|
||||
m_strength = strength;
|
||||
|
||||
this->classBegin();
|
||||
configureTiles();
|
||||
|
||||
emit strengthChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void WindowShadow::onViewVisibleChanged(bool visible)
|
||||
{
|
||||
if (visible && m_view) {
|
||||
configureTiles();
|
||||
}
|
||||
}
|
||||
|
||||
void WindowShadow::configureTiles()
|
||||
{
|
||||
}
|
||||
|
||||
TileSet WindowShadow::shadowTiles()
|
||||
{
|
||||
const qreal frameRadius = m_radius;
|
||||
const CompositeShadowParams params = lookupShadowParams(ShadowVeryLarge);
|
||||
|
||||
if (params.isNone())
|
||||
return TileSet();
|
||||
|
||||
auto withOpacity = [](const QColor &color, qreal opacity) -> QColor {
|
||||
QColor c(color);
|
||||
c.setAlphaF(opacity);
|
||||
return c;
|
||||
};
|
||||
|
||||
const QColor color = Qt::black;
|
||||
const qreal strength = m_strength;
|
||||
|
||||
const QSize boxSize = BoxShadowRenderer::calculateMinimumBoxSize(params.shadow1.radius)
|
||||
.expandedTo(BoxShadowRenderer::calculateMinimumBoxSize(params.shadow2.radius));
|
||||
|
||||
const qreal dpr = qApp->devicePixelRatio();
|
||||
|
||||
BoxShadowRenderer shadowRenderer;
|
||||
shadowRenderer.setBorderRadius(frameRadius);
|
||||
shadowRenderer.setBoxSize(boxSize);
|
||||
shadowRenderer.setDevicePixelRatio(dpr);
|
||||
|
||||
shadowRenderer.addShadow(params.shadow1.offset, params.shadow1.radius,
|
||||
withOpacity(color, params.shadow1.opacity * strength));
|
||||
shadowRenderer.addShadow(params.shadow2.offset, params.shadow2.radius,
|
||||
withOpacity(color, params.shadow2.opacity * strength));
|
||||
|
||||
QImage shadowTexture = shadowRenderer.render();
|
||||
|
||||
const QRect outerRect(QPoint(0, 0), shadowTexture.size() / dpr);
|
||||
|
||||
QRect boxRect(QPoint(0, 0), boxSize);
|
||||
boxRect.moveCenter(outerRect.center());
|
||||
|
||||
// Mask out inner rect.
|
||||
QPainter painter(&shadowTexture);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
int Shadow_Overlap = 3;
|
||||
const QMargins margins = QMargins(
|
||||
boxRect.left() - outerRect.left() - Shadow_Overlap - params.offset.x(),
|
||||
boxRect.top() - outerRect.top() - Shadow_Overlap - params.offset.y(),
|
||||
outerRect.right() - boxRect.right() - Shadow_Overlap + params.offset.x(),
|
||||
outerRect.bottom() - boxRect.bottom() - Shadow_Overlap + params.offset.y());
|
||||
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(Qt::black);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_DestinationOut);
|
||||
painter.drawRoundedRect(
|
||||
outerRect - margins,
|
||||
frameRadius,
|
||||
frameRadius);
|
||||
|
||||
// We're done.
|
||||
painter.end();
|
||||
|
||||
const QPoint innerRectTopLeft = outerRect.center();
|
||||
TileSet tiles = TileSet(
|
||||
QPixmap::fromImage(shadowTexture),
|
||||
innerRectTopLeft.x(),
|
||||
innerRectTopLeft.y(),
|
||||
1, 1);
|
||||
|
||||
return tiles;
|
||||
}
|
||||
|
||||
QMargins WindowShadow::shadowMargins(TileSet shadowTiles) const
|
||||
{
|
||||
const CompositeShadowParams params = lookupShadowParams(ShadowVeryLarge);
|
||||
if (params.isNone())
|
||||
return QMargins();
|
||||
|
||||
const QSize boxSize = BoxShadowRenderer::calculateMinimumBoxSize(params.shadow1.radius)
|
||||
.expandedTo(BoxShadowRenderer::calculateMinimumBoxSize(params.shadow2.radius));
|
||||
|
||||
const QSize shadowSize = BoxShadowRenderer::calculateMinimumShadowTextureSize(boxSize, params.shadow1.radius, params.shadow1.offset)
|
||||
.expandedTo(BoxShadowRenderer::calculateMinimumShadowTextureSize(boxSize, params.shadow2.radius, params.shadow2.offset));
|
||||
|
||||
const QRect shadowRect(QPoint(0, 0), shadowSize);
|
||||
|
||||
QRect boxRect(QPoint(0, 0), boxSize);
|
||||
boxRect.moveCenter(shadowRect.center());
|
||||
|
||||
int Shadow_Overlap = 4;
|
||||
QMargins margins(
|
||||
boxRect.left() - shadowRect.left() - Shadow_Overlap - params.offset.x(),
|
||||
boxRect.top() - shadowRect.top() - Shadow_Overlap - params.offset.y(),
|
||||
shadowRect.right() - boxRect.right() - Shadow_Overlap + params.offset.x(),
|
||||
shadowRect.bottom() - boxRect.bottom() - Shadow_Overlap + params.offset.y());
|
||||
|
||||
margins *= shadowTiles.pixmap(0).devicePixelRatio();
|
||||
|
||||
return margins;
|
||||
}
|
||||
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: revenmartin <revenmartin@gmail.com>
|
||||
*
|
||||
* This program 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
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WINDOWSHADOW_H
|
||||
#define WINDOWSHADOW_H
|
||||
|
||||
#include "tileset.h"
|
||||
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlParserStatus>
|
||||
#include <QRect>
|
||||
#include <QWindow>
|
||||
#include <QVector>
|
||||
|
||||
struct ShadowParams
|
||||
{
|
||||
ShadowParams() = default;
|
||||
|
||||
ShadowParams(const QPoint &offset, int radius, qreal opacity):
|
||||
offset(offset),
|
||||
radius(radius),
|
||||
opacity(opacity)
|
||||
{}
|
||||
|
||||
QPoint offset;
|
||||
int radius = 0;
|
||||
qreal opacity = 0;
|
||||
};
|
||||
|
||||
struct CompositeShadowParams
|
||||
{
|
||||
CompositeShadowParams() = default;
|
||||
|
||||
CompositeShadowParams(
|
||||
const QPoint &offset,
|
||||
const ShadowParams &shadow1,
|
||||
const ShadowParams &shadow2)
|
||||
: offset(offset)
|
||||
, shadow1(shadow1)
|
||||
, shadow2(shadow2) {}
|
||||
|
||||
bool isNone() const
|
||||
{ return qMax(shadow1.radius, shadow2.radius) == 0; }
|
||||
|
||||
QPoint offset;
|
||||
ShadowParams shadow1;
|
||||
ShadowParams shadow2;
|
||||
};
|
||||
|
||||
class WindowShadow : public QObject, public QQmlParserStatus
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QQmlParserStatus)
|
||||
Q_PROPERTY(QWindow *view READ view WRITE setView NOTIFY viewChanged)
|
||||
Q_PROPERTY(QRect geometry READ geometry WRITE setGeometry NOTIFY geometryChanged)
|
||||
Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
|
||||
Q_PROPERTY(qreal strength READ strength WRITE setStrength NOTIFY strengthChanged)
|
||||
|
||||
public:
|
||||
WindowShadow(QObject *parent = nullptr) noexcept;
|
||||
~WindowShadow() override;
|
||||
|
||||
static CompositeShadowParams lookupShadowParams(int shadowSizeEnum);
|
||||
|
||||
void classBegin() override;
|
||||
void componentComplete() override;
|
||||
|
||||
void setView(QWindow *view);
|
||||
QWindow *view() const;
|
||||
|
||||
void setGeometry(const QRect &rect);
|
||||
QRect geometry() const;
|
||||
|
||||
void setRadius(qreal value);
|
||||
qreal radius() { return m_radius; }
|
||||
|
||||
qreal strength() const;
|
||||
void setStrength(qreal strength);
|
||||
|
||||
private slots:
|
||||
void onViewVisibleChanged(bool);
|
||||
|
||||
private:
|
||||
void configureTiles();
|
||||
TileSet shadowTiles();
|
||||
|
||||
QMargins shadowMargins(TileSet) const;
|
||||
|
||||
signals:
|
||||
void geometryChanged();
|
||||
void enabledChanged();
|
||||
void viewChanged();
|
||||
void edgesChanged();
|
||||
void radiusChanged();
|
||||
void strengthChanged();
|
||||
|
||||
private:
|
||||
QWindow *m_view;
|
||||
QRect m_rect;
|
||||
TileSet m_shadowTiles;
|
||||
qreal m_radius = 10;
|
||||
qreal m_strength = 1.2;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue