remove current shadow implementation

This commit is contained in:
Peter Hartmann 2021-10-01 14:34:56 +02:00
parent c7eae4c3d1
commit 943ddb17bd
29 changed files with 1 additions and 2439 deletions

View File

@ -23,12 +23,8 @@
#include <QskTextLabel.h> #include <QskTextLabel.h>
#include <QskQuick.h> #include <QskQuick.h>
#include "kirigami/shadowedrectangle.h"
#include <QTimer> #include <QTimer>
QSK_SUBCONTROL( ShadowPositioner, Panel )
QSK_SUBCONTROL( MainContent, Panel ) QSK_SUBCONTROL( MainContent, Panel )
QSK_SUBCONTROL( MainContentGridBox, Panel ) QSK_SUBCONTROL( MainContentGridBox, Panel )
@ -63,59 +59,6 @@ namespace
}; };
} }
ShadowPositioner::ShadowPositioner( QQuickItem* parent )
: QskControl( parent )
{
setAutoLayoutChildren( true );
}
void ShadowPositioner::setGridBox( QskGridBox* gridBox )
{
m_gridBox = gridBox;
m_rectangles.reserve( m_gridBox->elementCount() );
for( int i = 0; i < m_gridBox->elementCount(); ++i )
{
auto r = new ShadowedRectangle( this );
r->setZ( 5 );
r->setColor( Qt::transparent );
r->shadow()->setColor( color( ShadowPositioner::Panel ) );
connect( qskSetup, &QskSetup::skinChanged, [this, r]()
{
r->shadow()->setColor( color( ShadowPositioner::Panel ) );
} );
r->shadow()->setSize( metric( ShadowPositioner::Panel | QskAspect::Size ) );
r->setOpacity( 0.1 );
auto shape = boxShapeHint( ShadowPositioner::Panel );
r->corners()->setTopLeft( shape.radius( Qt::TopLeftCorner ).width() );
r->corners()->setTopRight( shape.radius( Qt::TopRightCorner ).width() );
r->corners()->setBottomLeft( shape.radius( Qt::BottomLeftCorner ).width() );
r->corners()->setBottomRight( shape.radius( Qt::BottomRightCorner ).width() );
m_rectangles.append( r );
}
}
void ShadowPositioner::updateLayout()
{
auto mainContent = static_cast< QskLinearBox* >( parentItem() );
QTimer::singleShot( 0, this, [this, mainContent]()
{
const auto pos0 = mainContent->itemAtIndex( 1 )->position();
for( int i = 0; i < m_rectangles.count(); ++i )
{
const auto item = m_gridBox->itemAtIndex( i );
m_rectangles[i]->setPosition( pos0 + item->position() );
m_rectangles[i]->setSize( qskItemSize( item ) );
}
} );
}
MainContent::MainContent( QQuickItem* parent ) MainContent::MainContent( QQuickItem* parent )
: QskLinearBox( Qt::Vertical, parent ) : QskLinearBox( Qt::Vertical, parent )
{ {
@ -146,15 +89,6 @@ MainContent::MainContent( QQuickItem* parent )
addItem( topBar ); addItem( topBar );
addItem( gridBox ); addItem( gridBox );
m_shadowPositioner = new ShadowPositioner( this );
m_shadowPositioner->setGridBox( gridBox );
}
void MainContent::geometryChangeEvent( QskGeometryChangeEvent* event )
{
QskLinearBox::geometryChangeEvent( event );
m_shadowPositioner->polish();
} }
#include "moc_MainContent.cpp" #include "moc_MainContent.cpp"

View File

@ -8,25 +8,6 @@
#include <QskGridBox.h> #include <QskGridBox.h>
#include <QskLinearBox.h> #include <QskLinearBox.h>
class ShadowedRectangle;
class ShadowPositioner : public QskControl
{
Q_OBJECT
public:
QSK_SUBCONTROLS( Panel )
ShadowPositioner( QQuickItem* parent );
void updateLayout() override;
void setGridBox( QskGridBox* gridBox );
private:
QskGridBox* m_gridBox;
QVector< ShadowedRectangle* > m_rectangles;
};
class MainContentGridBox : public QskGridBox class MainContentGridBox : public QskGridBox
{ {
Q_OBJECT Q_OBJECT
@ -50,10 +31,6 @@ class MainContent : public QskLinearBox
MainContent( QQuickItem* parent ); MainContent( QQuickItem* parent );
protected:
void geometryChangeEvent( QskGeometryChangeEvent* ) override;
private: private:
QList< QskLinearBox* > m_columns; QList< QskLinearBox* > m_columns;
ShadowPositioner* m_shadowPositioner;
}; };

View File

@ -129,9 +129,6 @@ void Skin::initHints( const Palette& palette )
// boxes (including shadow): // boxes (including shadow):
ed.setPadding( Box::Panel, 15 ); ed.setPadding( Box::Panel, 15 );
ed.setMetric( ShadowPositioner::Panel | QskAspect::Size, 15 );
ed.setBoxShape( ShadowPositioner::Panel, 6 );
// content in boxes (indoor temperature, humidity etc.): // content in boxes (indoor temperature, humidity etc.):
ed.setFontRole( UsageBox::Separator, QskSkin::SmallFont ); ed.setFontRole( UsageBox::Separator, QskSkin::SmallFont );
@ -200,6 +197,5 @@ void Skin::initHints( const Palette& palette )
ed.setBoxBorderColors( UsageDiagramBox::DaysBox, palette.weekdayBox ); ed.setBoxBorderColors( UsageDiagramBox::DaysBox, palette.weekdayBox );
ed.setColor( QskTextLabel::Text, palette.text ); ed.setColor( QskTextLabel::Text, palette.text );
ed.setColor( UsageDiagramBox::DayText, palette.text ); ed.setColor( UsageDiagramBox::DayText, palette.text );
ed.setColor( ShadowPositioner::Panel, palette.shadow );
ed.setGradient( CircularProgressBar::Groove, palette.circularProgressBarGroove ); ed.setGradient( CircularProgressBar::Groove, palette.circularProgressBarGroove );
} }

View File

@ -74,4 +74,4 @@ SOURCES += \
RESOURCES += \ RESOURCES += \
images.qrc \ images.qrc \
fonts.qrc \ fonts.qrc \
kirigami/scenegraph/shaders/shaders.qrc shaders.qrc

View File

@ -1,50 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "paintedrectangleitem.h"
#include <QPainter>
PaintedRectangleItem::PaintedRectangleItem(QQuickItem* parent)
: QQuickPaintedItem(parent)
{
}
void PaintedRectangleItem::setColor(const QColor& color)
{
m_color = color;
update();
}
void PaintedRectangleItem::setRadius(qreal radius)
{
m_radius = radius;
update();
}
void PaintedRectangleItem::setBorderColor(const QColor& color)
{
m_borderColor = color;
update();
}
void PaintedRectangleItem::setBorderWidth(qreal width)
{
m_borderWidth = width;
update();
}
void PaintedRectangleItem::paint(QPainter* painter)
{
painter->setRenderHint(QPainter::Antialiasing, true);
painter->setBrush(m_color);
if (m_borderWidth > 0.0) {
painter->setPen(QPen(m_borderColor, m_borderWidth));
} else {
painter->setPen(Qt::transparent);
}
painter->drawRoundedRect(m_borderWidth / 2, m_borderWidth / 2, width() - m_borderWidth, height() - m_borderWidth, m_radius, m_radius);
}

View File

@ -1,43 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef PAINTEDRECTANGLEITEM_H
#define PAINTEDRECTANGLEITEM_H
#include <QQuickPaintedItem>
/**
* A rectangle with a border and rounded corners, rendered through QPainter.
*
* This is a helper used by ShadowedRectangle as fallback for when software
* rendering is used, which means our shaders cannot be used.
*
* Since we cannot actually use QSGPaintedNode, we need to do some trickery
* using QQuickPaintedItem as a child of ShadowedRectangle.
*
* \warning This item is **not** intended as a general purpose item.
*/
class PaintedRectangleItem : public QQuickPaintedItem
{
Q_OBJECT
public:
explicit PaintedRectangleItem(QQuickItem *parent = nullptr);
void setColor(const QColor &color);
void setRadius(qreal radius);
void setBorderColor(const QColor &color);
void setBorderWidth(qreal width);
void paint(QPainter *painter) override;
private:
QColor m_color;
qreal m_radius = 0.0;
QColor m_borderColor;
qreal m_borderWidth = 0.0;
};
#endif // PAINTEDRECTANGLEITEM_H

View File

@ -1,26 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
// This file contains common directives needed for the shaders to work.
// It is included as the very first bit in the shader.
// Important: If a specific GLSL version is needed, it should be set in this
// file.
// This file is intended for desktop OpenGL version 2.1 or greater.
#version 120
#ifndef lowp
#define lowp
#endif
#ifndef mediump
#define mediump
#endif
#ifndef highp
#define highp mediump
#endif

View File

@ -1,16 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
// This file contains common directives needed for the shaders to work.
// It is included as the very first bit in the shader.
// Important: If a specific GLSL version is needed, it should be set in this
// file.
// This file is intended for desktop OpenGL version 4.5 or greater.
#version 450
#define CORE_PROFILE

View File

@ -1,16 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
// This file contains common directives needed for the shaders to work.
// It is included as the very first bit in the shader.
// Important: If a specific GLSL version is needed, it should be set in this
// file.
// This file is intended for OpenGLES version 2.0 or greater.
#version 100
#extension GL_OES_standard_derivatives : enable

View File

@ -1,240 +0,0 @@
// SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
// SPDX-FileCopyrightText: 2017 Inigo Quilez
//
// SPDX-License-Identifier: MIT
//
// This file is based on
// https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
//if not GLES
// include "desktop_header.glsl"
//else
// include "es_header.glsl"
// A maximum point count to be used for sdf_polygon input arrays.
// Unfortunately even function inputs require a fixed size at declaration time
// for arrays, unless we were to use OpenGL 4.5.
// Since the polygon is most likely to be defined in a uniform, this should be
// at least less than MAX_FRAGMENT_UNIFORM_COMPONENTS / 2 (since we need vec2).
#define SDF_POLYGON_MAX_POINT_COUNT 400
/*********************************
Shapes
*********************************/
// Distance field for a circle.
//
// \param point A point on the distance field.
// \param radius The radius of the circle.
//
// \return The signed distance from point to the circle. If negative, point is
// inside the circle.
lowp float sdf_circle(in lowp vec2 point, in lowp float radius)
{
return length(point) - radius;
}
// Distance field for a triangle.
//
// \param point A point on the distance field.
// \param p0 The first vertex of the triangle.
// \param p0 The second vertex of the triangle.
// \param p0 The third vertex of the triangle.
//
// \note The ordering of the three vertices does not matter.
//
// \return The signed distance from point to triangle. If negative, point is
// inside the triangle.
lowp float sdf_triangle(in lowp vec2 point, in lowp vec2 p0, in lowp vec2 p1, in lowp vec2 p2)
{
lowp vec2 e0 = p1 - p0;
lowp vec2 e1 = p2 - p1;
lowp vec2 e2 = p0 - p2;
lowp vec2 v0 = point - p0;
lowp vec2 v1 = point - p1;
lowp vec2 v2 = point - p2;
lowp vec2 pq0 = v0 - e0 * clamp( dot(v0, e0) / dot(e0, e0), 0.0, 1.0 );
lowp vec2 pq1 = v1 - e1 * clamp( dot(v1, e1) / dot(e1, e1), 0.0, 1.0 );
lowp vec2 pq2 = v2 - e2 * clamp( dot(v2, e2) / dot(e2, e2), 0.0, 1.0 );
lowp float s = sign( e0.x*e2.y - e0.y*e2.x );
lowp vec2 d = min(min(vec2(dot(pq0,pq0), s*(v0.x*e0.y-v0.y*e0.x)),
vec2(dot(pq1,pq1), s*(v1.x*e1.y-v1.y*e1.x))),
vec2(dot(pq2,pq2), s*(v2.x*e2.y-v2.y*e2.x)));
return -sqrt(d.x)*sign(d.y);
}
// Distance field for a rectangle.
//
// \param point A point on the distance field.
// \param rect A vec2 with the size of the rectangle.
//
// \return The signed distance from point to rectangle. If negative, point is
// inside the rectangle.
lowp float sdf_rectangle(in lowp vec2 point, in lowp vec2 rect)
{
lowp vec2 d = abs(point) - rect;
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
}
// Distance field for a rectangle with rounded corners.
//
// \param point The point to calculate the distance of.
// \param rect The rectangle to calculate the distance of.
// \param radius A vec4 with the radius of each corner. Order is top right, bottom right, top left, bottom left.
//
// \return The signed distance from point to rectangle. If negative, point is
// inside the rectangle.
lowp float sdf_rounded_rectangle(in lowp vec2 point, in lowp vec2 rect, in lowp vec4 radius)
{
radius.xy = (point.x > 0.0) ? radius.xy : radius.zw;
radius.x = (point.y > 0.0) ? radius.x : radius.y;
lowp vec2 d = abs(point) - rect + radius.x;
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - radius.x;
}
/*********************
Operators
*********************/
// Convert a distance field to an annular (hollow) distance field.
//
// \param sdf The result of an sdf shape to convert.
// \param thickness The thickness of the resulting shape.
//
// \return The value of sdf modified to an annular shape.
lowp float sdf_annular(in lowp float sdf, in lowp float thickness)
{
return abs(sdf) - thickness;
}
// Union two sdf shapes together.
//
// \param sdf1 The first sdf shape.
// \param sdf2 The second sdf shape.
//
// \return The union of sdf1 and sdf2, that is, the distance to both sdf1 and
// sdf2.
lowp float sdf_union(in lowp float sdf1, in lowp float sdf2)
{
return min(sdf1, sdf2);
}
// Subtract two sdf shapes.
//
// \param sdf1 The first sdf shape.
// \param sdf2 The second sdf shape.
//
// \return sdf1 with sdf2 subtracted from it.
lowp float sdf_subtract(in lowp float sdf1, in lowp float sdf2)
{
return max(sdf1, -sdf2);
}
// Intersect two sdf shapes.
//
// \param sdf1 The first sdf shape.
// \param sdf2 The second sdf shape.
//
// \return The intersection between sdf1 and sdf2, that is, the area where both
// sdf1 and sdf2 provide the same distance value.
lowp float sdf_intersect(in lowp float sdf1, in lowp float sdf2)
{
return max(sdf1, sdf2);
}
// Smoothly intersect two sdf shapes.
//
// \param sdf1 The first sdf shape.
// \param sdf2 The second sdf shape.
// \param smoothing The amount of smoothing to apply.
//
// \return A smoothed version of the intersect operation.
lowp float sdf_intersect_smooth(in lowp float sdf1, in lowp float sdf2, in lowp float smoothing)
{
lowp float h = clamp(0.5 - 0.5 * (sdf1 - sdf2) / smoothing, 0.0, 1.0);
return mix(sdf1, sdf2, h) + smoothing * h * (1.0 - h);
}
// Round an sdf shape.
//
// \param sdf The sdf shape to round.
// \param amount The amount of rounding to apply.
//
// \return The rounded shape of sdf.
// Note that rounding happens by basically selecting an isoline of sdf,
// therefore, the resulting shape may be larger than the input shape.
lowp float sdf_round(in lowp float sdf, in lowp float amount)
{
return sdf - amount;
}
// Convert an sdf shape to an outline of its shape.
//
// \param sdf The sdf shape to turn into an outline.
//
// \return The outline of sdf.
lowp float sdf_outline(in lowp float sdf)
{
return abs(sdf);
}
/********************
Convenience
********************/
// A constant to represent a "null" value of an sdf.
//
// Since 0 is a point exactly on the outline of an sdf shape, and negative
// values are inside the shape, this uses a very large positive constant to
// indicate a value that is really far away from the actual sdf shape.
const lowp float sdf_null = 99999.0;
// A constant for a default level of smoothing when rendering an sdf.
//
// This
const lowp float sdf_default_smoothing = 0.625;
// Render an sdf shape alpha-blended onto an existing color.
//
// This is an overload of sdf_render(float, vec4, vec4) that allows specifying a
// blending amount and a smoothing amount.
//
// \param alpha The alpha to use for blending.
// \param smoothing The amount of smoothing to apply to the sdf.
//
lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor, in lowp float alpha, in lowp float smoothing)
{
lowp float g = fwidth(sdf);
return mix(sourceColor, sdfColor, alpha * (1.0 - smoothstep(-smoothing * g, smoothing * g, sdf)));
}
// Render an sdf shape.
//
// This will render the sdf shape on top of whatever source color is input,
// making sure to apply smoothing if desired.
//
// \param sdf The sdf shape to render.
// \param sourceColor The source color to render on top of.
// \param sdfColor The color to use for rendering the sdf shape.
//
// \return sourceColor with the sdf shape rendered on top.
lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor)
{
return sdf_render(sdf, sourceColor, sdfColor, 1.0, sdf_default_smoothing);
}
// Render an sdf shape.
//
// This is an overload of sdf_render(float, vec4, vec4) that allows specifying a
// smoothing amount.
//
// \param smoothing The amount of smoothing to apply to the sdf.
//
lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor, in lowp float smoothing)
{
return sdf_render(sdf, sourceColor, sdfColor, 1.0, smoothing);
}

View File

@ -1,239 +0,0 @@
// SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
// SPDX-FileCopyrightText: 2017 Inigo Quilez
//
// SPDX-License-Identifier: MIT
//
// This file is based on
// https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
//if not GLES
// include "desktop_header.glsl"
//else
// include "es_header.glsl"
// A maximum point count to be used for sdf_polygon input arrays.
// Unfortunately even function inputs require a fixed size at declaration time
// for arrays, unless we were to use OpenGL 4.5.
// Since the polygon is most likely to be defined in a uniform, this should be
// at least less than MAX_FRAGMENT_UNIFORM_COMPONENTS / 2 (since we need vec2).
#define SDF_POLYGON_MAX_POINT_COUNT 400
/*********************************
Shapes
*********************************/
// Distance field for a circle.
//
// \param point A point on the distance field.
// \param radius The radius of the circle.
//
// \return The signed distance from point to the circle. If negative, point is
// inside the circle.
lowp float sdf_circle(in lowp vec2 point, in lowp float radius)
{
return length(point) - radius;
}
// Distance field for a triangle.
//
// \param point A point on the distance field.
// \param p0 The first vertex of the triangle.
// \param p0 The second vertex of the triangle.
// \param p0 The third vertex of the triangle.
//
// \note The ordering of the three vertices does not matter.
//
// \return The signed distance from point to triangle. If negative, point is
// inside the triangle.
lowp float sdf_triangle(in lowp vec2 point, in lowp vec2 p0, in lowp vec2 p1, in lowp vec2 p2)
{
lowp vec2 e0 = p1 - p0;
lowp vec2 e1 = p2 - p1;
lowp vec2 e2 = p0 - p2;
lowp vec2 v0 = point - p0;
lowp vec2 v1 = point - p1;
lowp vec2 v2 = point - p2;
lowp vec2 pq0 = v0 - e0 * clamp( dot(v0, e0) / dot(e0, e0), 0.0, 1.0 );
lowp vec2 pq1 = v1 - e1 * clamp( dot(v1, e1) / dot(e1, e1), 0.0, 1.0 );
lowp vec2 pq2 = v2 - e2 * clamp( dot(v2, e2) / dot(e2, e2), 0.0, 1.0 );
lowp float s = sign( e0.x*e2.y - e0.y*e2.x );
lowp vec2 d = min(min(vec2(dot(pq0,pq0), s*(v0.x*e0.y-v0.y*e0.x)),
vec2(dot(pq1,pq1), s*(v1.x*e1.y-v1.y*e1.x))),
vec2(dot(pq2,pq2), s*(v2.x*e2.y-v2.y*e2.x)));
return -sqrt(d.x)*sign(d.y);
}
// Distance field for a rectangle.
//
// \param point A point on the distance field.
// \param rect A vec2 with the size of the rectangle.
//
// \return The signed distance from point to rectangle. If negative, point is
// inside the rectangle.
lowp float sdf_rectangle(in lowp vec2 point, in lowp vec2 rect)
{
lowp vec2 d = abs(point) - rect;
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
}
// Distance field for a rectangle with rounded corners.
//
// \param point The point to calculate the distance of.
// \param rect The rectangle to calculate the distance of.
// \param radius A vec4 with the radius of each corner. Order is top right, bottom right, top left, bottom left.
//
// \return The signed distance from point to rectangle. If negative, point is
// inside the rectangle.
lowp float sdf_rounded_rectangle(in lowp vec2 point, in lowp vec2 rect, in lowp vec4 radius)
{
radius.xy = (point.x > 0.0) ? radius.xy : radius.zw;
radius.x = (point.y > 0.0) ? radius.x : radius.y;
lowp vec2 d = abs(point) - rect + radius.x;
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - radius.x;
}
/*********************
Operators
*********************/
// Convert a distance field to an annular (hollow) distance field.
//
// \param sdf The result of an sdf shape to convert.
// \param thickness The thickness of the resulting shape.
//
// \return The value of sdf modified to an annular shape.
lowp float sdf_annular(in lowp float sdf, in lowp float thickness)
{
return abs(sdf) - thickness;
}
// Union two sdf shapes together.
//
// \param sdf1 The first sdf shape.
// \param sdf2 The second sdf shape.
//
// \return The union of sdf1 and sdf2, that is, the distance to both sdf1 and
// sdf2.
lowp float sdf_union(in lowp float sdf1, in lowp float sdf2)
{
return min(sdf1, sdf2);
}
// Subtract two sdf shapes.
//
// \param sdf1 The first sdf shape.
// \param sdf2 The second sdf shape.
//
// \return sdf1 with sdf2 subtracted from it.
lowp float sdf_subtract(in lowp float sdf1, in lowp float sdf2)
{
return max(sdf1, -sdf2);
}
// Intersect two sdf shapes.
//
// \param sdf1 The first sdf shape.
// \param sdf2 The second sdf shape.
//
// \return The intersection between sdf1 and sdf2, that is, the area where both
// sdf1 and sdf2 provide the same distance value.
lowp float sdf_intersect(in lowp float sdf1, in lowp float sdf2)
{
return max(sdf1, sdf2);
}
// Smoothly intersect two sdf shapes.
//
// \param sdf1 The first sdf shape.
// \param sdf2 The second sdf shape.
// \param smoothing The amount of smoothing to apply.
//
// \return A smoothed version of the intersect operation.
lowp float sdf_intersect_smooth(in lowp float sdf1, in lowp float sdf2, in lowp float smoothing)
{
lowp float h = clamp(0.5 - 0.5 * (sdf1 - sdf2) / smoothing, 0.0, 1.0);
return mix(sdf1, sdf2, h) + smoothing * h * (1.0 - h);
}
// Round an sdf shape.
//
// \param sdf The sdf shape to round.
// \param amount The amount of rounding to apply.
//
// \return The rounded shape of sdf.
// Note that rounding happens by basically selecting an isoline of sdf,
// therefore, the resulting shape may be larger than the input shape.
lowp float sdf_round(in lowp float sdf, in lowp float amount)
{
return sdf - amount;
}
// Convert an sdf shape to an outline of its shape.
//
// \param sdf The sdf shape to turn into an outline.
//
// \return The outline of sdf.
lowp float sdf_outline(in lowp float sdf)
{
return abs(sdf);
}
/********************
Convenience
********************/
// A constant to represent a "null" value of an sdf.
//
// Since 0 is a point exactly on the outline of an sdf shape, and negative
// values are inside the shape, this uses a very large positive constant to
// indicate a value that is really far away from the actual sdf shape.
const lowp float sdf_null = 99999.0;
// A constant for a default level of smoothing when rendering an sdf.
//
// This
const lowp float sdf_default_smoothing = 0.625;
// Render an sdf shape alpha-blended onto an existing color.
//
// This is an overload of sdf_render(float, vec4, vec4) that allows specifying a
// blending amount and a smoothing amount.
//
// \param alpha The alpha to use for blending.
// \param smoothing The amount of smoothing to apply to the sdf.
//
lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor, in lowp float alpha, in lowp float smoothing)
{
return mix(sourceColor, sdfColor, alpha * (1.0 - clamp(sdf * 300.0, 0.0, 1.0)));
}
// Render an sdf shape.
//
// This will render the sdf shape on top of whatever source color is input,
// making sure to apply smoothing if desired.
//
// \param sdf The sdf shape to render.
// \param sourceColor The source color to render on top of.
// \param sdfColor The color to use for rendering the sdf shape.
//
// \return sourceColor with the sdf shape rendered on top.
lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor)
{
return sdf_render(sdf, sourceColor, sdfColor, 1.0, sdf_default_smoothing);
}
// Render an sdf shape.
//
// This is an overload of sdf_render(float, vec4, vec4) that allows specifying a
// smoothing amount.
//
// \param smoothing The amount of smoothing to apply to the sdf.
//
lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor, in lowp float smoothing)
{
return sdf_render(sdf, sourceColor, sdfColor, 1.0, smoothing);
}

View File

@ -1,26 +0,0 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/org/kde/kirigami/shaders">
<file>header_es.glsl</file>
<file>header_desktop.glsl</file>
<file>header_desktop_core.glsl</file>
<file>sdf.glsl</file>
<file>sdf_lowpower.glsl</file>
<file alias="sdf_core.glsl">sdf.glsl</file>
<file>shadowedrectangle.vert</file>
<file alias="shadowedrectangle_core.vert">shadowedrectangle.vert</file>
<file>shadowedrectangle.frag</file>
<file>shadowedrectangle_lowpower.frag</file>
<file alias="shadowedrectangle_core.frag">shadowedrectangle.frag</file>
<file>shadowedborderrectangle.frag</file>
<file>shadowedborderrectangle_lowpower.frag</file>
<file alias="shadowedborderrectangle_core.frag">shadowedborderrectangle.frag</file>
<file>shadowedtexture.frag</file>
<file>shadowedtexture_lowpower.frag</file>
<file alias="shadowedtexture_core.frag">shadowedtexture.frag</file>
<file>shadowedbordertexture.frag</file>
<file>shadowedbordertexture_lowpower.frag</file>
<file alias="shadowedbordertexture_core.frag">shadowedbordertexture.frag</file>
</qresource>
</RCC>

View File

@ -1,73 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
// See sdf.glsl for the SDF related functions.
// This shader renders a rectangle with rounded corners and a shadow below it.
// In addition it renders a border around it.
uniform lowp float opacity;
uniform lowp float size;
uniform lowp vec4 radius;
uniform lowp vec4 color;
uniform lowp vec4 shadowColor;
uniform lowp vec2 offset;
uniform lowp vec2 aspect;
uniform lowp float borderWidth;
uniform lowp vec4 borderColor;
#ifdef CORE_PROFILE
in lowp vec2 uv;
out lowp vec4 out_color;
#else
varying lowp vec2 uv;
#define out_color gl_FragColor
#endif
const lowp float minimum_shadow_radius = 0.05;
void main()
{
// Scaling factor that is the inverse of the amount of scaling applied to the geometry.
lowp float inverse_scale = 1.0 / (1.0 + size + length(offset) * 2.0);
// Correction factor to round the corners of a larger shadow.
// We want to account for size in regards to shadow radius, so that a larger shadow is
// more rounded, but only if we are not already rounding the corners due to corner radius.
lowp vec4 size_factor = 0.5 * (minimum_shadow_radius / max(radius, minimum_shadow_radius));
lowp vec4 shadow_radius = radius + size * size_factor;
lowp vec4 col = vec4(0.0);
// Calculate the shadow's distance field.
lowp float shadow = sdf_rounded_rectangle(uv - offset * 2.0 * inverse_scale, aspect * inverse_scale, shadow_radius * inverse_scale);
// Render it, interpolating the color over the distance.
col = mix(col, shadowColor * sign(size), 1.0 - smoothstep(-size * 0.5, size * 0.5, shadow));
// Scale corrected corner radius
lowp vec4 corner_radius = radius * inverse_scale;
// Calculate the outer rectangle distance field.
lowp float outer_rect = sdf_rounded_rectangle(uv, aspect * inverse_scale, corner_radius);
// First, remove anything that was rendered by the shadow if it is inside the rectangle.
// This allows us to use colors with alpha without rendering artifacts.
col = sdf_render(outer_rect, col, vec4(0.0));
// Then, render it again but this time with the proper color and properly alpha blended.
col = sdf_render(outer_rect, col, borderColor);
// The inner rectangle distance field is the outer reduces by twice the border size.
lowp float inner_rect = outer_rect + (borderWidth * inverse_scale) * 2.0;
// Like above, but this time cut out the inner rectangle.
col = sdf_render(inner_rect, col, vec4(0.0));
// Finally, render the inner rectangle.
col = sdf_render(inner_rect, col, color);
out_color = col * opacity;
}

View File

@ -1,47 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
// See sdf.glsl for the SDF related functions.
// This is a version of shadowedborderrectangle.frag for extremely low powered
// hardware (PinePhone). It does not draw a shadow and also eliminates alpha
// blending.
uniform lowp float opacity;
uniform lowp float size;
uniform lowp vec4 radius;
uniform lowp vec4 color;
uniform lowp vec4 shadowColor;
uniform lowp vec2 offset;
uniform lowp vec2 aspect;
uniform lowp float borderWidth;
uniform lowp vec4 borderColor;
#ifdef CORE_PROFILE
in lowp vec2 uv;
out lowp vec4 out_color;
#else
varying lowp vec2 uv;
#define out_color gl_FragColor
#define texture texture2D
#endif
void main()
{
lowp vec4 col = vec4(0.0);
// Calculate the outer rectangle distance field.
lowp float outer_rect = sdf_rounded_rectangle(uv, aspect, radius);
col = sdf_render(outer_rect, col, vec4(borderColor.rgb, 1.0));
// The inner distance field is the outer reduced by border width.
lowp float inner_rect = outer_rect + borderWidth * 2.0;
col = sdf_render(inner_rect, col, vec4(color.rgb, 1.0));
out_color = col * opacity;
}

View File

@ -1,83 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
// See sdf.glsl for the SDF related functions.
// This shader renders a rectangle with rounded corners and a shadow below it.
// In addition it renders a border around it.
uniform lowp float opacity;
uniform lowp float size;
uniform lowp vec4 radius;
uniform lowp vec4 color;
uniform lowp vec4 shadowColor;
uniform lowp vec2 offset;
uniform lowp vec2 aspect;
uniform lowp float borderWidth;
uniform lowp vec4 borderColor;
uniform sampler2D textureSource;
#ifdef CORE_PROFILE
in lowp vec2 uv;
out lowp vec4 out_color;
#else
varying lowp vec2 uv;
#define out_color gl_FragColor
#define texture texture2D
#endif
const lowp float minimum_shadow_radius = 0.05;
void main()
{
// Scaling factor that is the inverse of the amount of scaling applied to the geometry.
lowp float inverse_scale = 1.0 / (1.0 + size + length(offset) * 2.0);
// Correction factor to round the corners of a larger shadow.
// We want to account for size in regards to shadow radius, so that a larger shadow is
// more rounded, but only if we are not already rounding the corners due to corner radius.
lowp vec4 size_factor = 0.5 * (minimum_shadow_radius / max(radius, minimum_shadow_radius));
lowp vec4 shadow_radius = radius + size * size_factor;
lowp vec4 col = vec4(0.0);
// Calculate the shadow's distance field.
lowp float shadow = sdf_rounded_rectangle(uv - offset * 2.0 * inverse_scale, aspect * inverse_scale, shadow_radius * inverse_scale);
// Render it, interpolating the color over the distance.
col = mix(col, shadowColor * sign(size), 1.0 - smoothstep(-size * 0.5, size * 0.5, shadow));
// Scale corrected corner radius
lowp vec4 corner_radius = radius * inverse_scale;
// Calculate the outer rectangle distance field.
lowp float outer_rect = sdf_rounded_rectangle(uv, aspect * inverse_scale, corner_radius);
// First, remove anything that was rendered by the shadow if it is inside the rectangle.
// This allows us to use colors with alpha without rendering artifacts.
col = sdf_render(outer_rect, col, vec4(0.0));
// Then, render it again but this time with the proper color and properly alpha blended.
col = sdf_render(outer_rect, col, borderColor);
// The inner rectangle distance field is the outer reduced by twice the border width.
lowp float inner_rect = outer_rect + (borderWidth * inverse_scale) * 2.0;
// Like above, but this time cut out the inner rectangle.
col = sdf_render(inner_rect, col, vec4(0.0));
// Finally, render the inner rectangle.
col = sdf_render(inner_rect, col, color);
// Slightly increase the size of the inner rectangle, to avoid issues with anti-aliasing.
inner_rect = inner_rect - 0.005;
// Sample the texture, then blend it on top of the background color.
lowp vec2 texture_uv = ((uv / aspect) + (1.0 * inverse_scale)) / (2.0 * inverse_scale);
lowp vec4 texture_color = texture(textureSource, texture_uv);
col = sdf_render(inner_rect, col, texture_color, texture_color.a, sdf_default_smoothing / 2.0);
out_color = col * opacity;
}

View File

@ -1,53 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
// See sdf.glsl for the SDF related functions.
// This shader renders a rectangle with rounded corners and a shadow below it.
// In addition it renders a border around it.
uniform lowp float opacity;
uniform lowp float size;
uniform lowp vec4 radius;
uniform lowp vec4 color;
uniform lowp vec4 shadowColor;
uniform lowp vec2 offset;
uniform lowp vec2 aspect;
uniform lowp float borderWidth;
uniform lowp vec4 borderColor;
uniform sampler2D textureSource;
#ifdef CORE_PROFILE
in lowp vec2 uv;
out lowp vec4 out_color;
#else
varying lowp vec2 uv;
#define out_color gl_FragColor
#define texture texture2D
#endif
const lowp float minimum_shadow_radius = 0.05;
void main()
{
lowp vec4 col = vec4(0.0);
// Calculate the outer rectangle distance field.
lowp float outer_rect = sdf_rounded_rectangle(uv, aspect, radius);
// Render it, cancelling out any alpha components.
col = sdf_render(outer_rect, col, vec4(borderColor.rgb, 1.0));
// Inner rectangle distance field equals outer reduced by twice the border width
lowp float inner_rect = outer_rect + borderWidth * 2.0;
// Sample the texture, then render it on top of the background color.
lowp vec2 texture_uv = ((uv / aspect) + 1.0) / 2.0;
lowp vec4 texture_color = vec4(texture(textureSource, texture_uv).rgb, 1.0);
col = sdf_render(inner_rect, col, texture_color, texture_color.a, sdf_default_smoothing / 2.0);
out_color = col * opacity;
}

View File

@ -1,58 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
// See sdf.glsl for the SDF related functions.
// This shader renders a rectangle with rounded corners and a shadow below it.
uniform lowp float opacity;
uniform lowp float size;
uniform lowp vec4 radius;
uniform lowp vec4 color;
uniform lowp vec4 shadowColor;
uniform lowp vec2 offset;
uniform lowp vec2 aspect;
#ifdef CORE_PROFILE
in lowp vec2 uv;
out lowp vec4 out_color;
#else
varying lowp vec2 uv;
#define out_color gl_FragColor
#endif
const lowp float minimum_shadow_radius = 0.05;
void main()
{
// Scaling factor that is the inverse of the amount of scaling applied to the geometry.
lowp float inverse_scale = 1.0 / (1.0 + size + length(offset) * 2.0);
// Correction factor to round the corners of a larger shadow.
// We want to account for size in regards to shadow radius, so that a larger shadow is
// more rounded, but only if we are not already rounding the corners due to corner radius.
lowp vec4 size_factor = 0.5 * (minimum_shadow_radius / max(radius, minimum_shadow_radius));
lowp vec4 shadow_radius = radius + size * size_factor;
lowp vec4 col = vec4(0.0);
// Calculate the shadow's distance field.
lowp float shadow = sdf_rounded_rectangle(uv - offset * 2.0 * inverse_scale, aspect * inverse_scale, shadow_radius * inverse_scale);
// Render it, interpolating the color over the distance.
col = mix(col, shadowColor * sign(size), 1.0 - smoothstep(-size * 0.5, size * 0.5, shadow));
// Calculate the main rectangle distance field.
lowp float rect = sdf_rounded_rectangle(uv, aspect * inverse_scale, radius * inverse_scale);
// First, remove anything that was rendered by the shadow if it is inside the rectangle.
// This allows us to use colors with alpha without rendering artifacts.
col = sdf_render(rect, col, vec4(0.0));
// Then, render it again but this time with the proper color and properly alpha blended.
col = sdf_render(rect, col, color);
out_color = col * opacity;
}

View File

@ -1,23 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
uniform highp mat4 matrix;
uniform lowp vec2 aspect;
#ifdef CORE_PROFILE
in highp vec4 in_vertex;
in mediump vec2 in_uv;
out mediump vec2 uv;
#else
attribute highp vec4 in_vertex;
attribute mediump vec2 in_uv;
varying mediump vec2 uv;
#endif
void main() {
uv = (-1.0 + 2.0 * in_uv) * aspect;
gl_Position = matrix * in_vertex;
}

View File

@ -1,39 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
// See sdf.glsl for the SDF related functions.
// This is a version of shadowedrectangle.frag meant for very low power hardware
// (PinePhone). It does not render a shadow and does not do alpha blending.
uniform lowp float opacity;
uniform lowp float size;
uniform lowp vec4 radius;
uniform lowp vec4 color;
uniform lowp vec4 shadowColor;
uniform lowp vec2 offset;
uniform lowp vec2 aspect;
#ifdef CORE_PROFILE
in lowp vec2 uv;
out lowp vec4 out_color;
#else
varying lowp vec2 uv;
#define out_color gl_FragColor
#endif
void main()
{
lowp vec4 col = vec4(0.0);
// Calculate the main rectangle distance field.
lowp float rect = sdf_rounded_rectangle(uv, aspect, radius);
// Render it, cancelling out any alpha component.
col = sdf_render(rect, col, vec4(color.rgb, 1.0));
out_color = col * opacity;
}

View File

@ -1,66 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
// See sdf.glsl for the SDF related functions.
// This shader renders a texture on top of a rectangle with rounded corners and
// a shadow below it.
uniform lowp float opacity;
uniform lowp float size;
uniform lowp vec4 radius;
uniform lowp vec4 color;
uniform lowp vec4 shadowColor;
uniform lowp vec2 offset;
uniform lowp vec2 aspect;
uniform sampler2D textureSource;
#ifdef CORE_PROFILE
in lowp vec2 uv;
out lowp vec4 out_color;
#else
varying lowp vec2 uv;
#define out_color gl_FragColor
#define texture texture2D
#endif
const lowp float minimum_shadow_radius = 0.05;
void main()
{
// Scaling factor that is the inverse of the amount of scaling applied to the geometry.
lowp float inverse_scale = 1.0 / (1.0 + size + length(offset) * 2.0);
// Correction factor to round the corners of a larger shadow.
// We want to account for size in regards to shadow radius, so that a larger shadow is
// more rounded, but only if we are not already rounding the corners due to corner radius.
lowp vec4 size_factor = 0.5 * (minimum_shadow_radius / max(radius, minimum_shadow_radius));
lowp vec4 shadow_radius = radius + size * size_factor;
lowp vec4 col = vec4(0.0);
// Calculate the shadow's distance field.
lowp float shadow = sdf_rounded_rectangle(uv - offset * 2.0 * inverse_scale, aspect * inverse_scale, shadow_radius * inverse_scale);
// Render it, interpolating the color over the distance.
col = mix(col, shadowColor * sign(size), 1.0 - smoothstep(-size * 0.5, size * 0.5, shadow));
// Calculate the main rectangle distance field.
lowp float rect = sdf_rounded_rectangle(uv, aspect * inverse_scale, radius * inverse_scale);
// First, remove anything that was rendered by the shadow if it is inside the rectangle.
// This allows us to use colors with alpha without rendering artifacts.
col = sdf_render(rect, col, vec4(0.0));
// Then, render it again but this time with the proper color.
col = sdf_render(rect, col, color);
// Sample the texture, then blend it on top of the background color.
lowp vec2 texture_uv = ((uv / aspect) + (1.0 * inverse_scale)) / (2.0 * inverse_scale);
lowp vec4 texture_color = texture(textureSource, texture_uv);
col = sdf_render(rect, col, texture_color, texture_color.a, sdf_default_smoothing);
out_color = col * opacity;
}

View File

@ -1,44 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
// See sdf.glsl for the SDF related functions.
// This shader renders a texture on top of a rectangle with rounded corners and
// a shadow below it.
uniform lowp float opacity;
uniform lowp float size;
uniform lowp vec4 radius;
uniform lowp vec4 color;
uniform lowp vec4 shadowColor;
uniform lowp vec2 offset;
uniform lowp vec2 aspect;
uniform sampler2D textureSource;
#ifdef CORE_PROFILE
in lowp vec2 uv;
out lowp vec4 out_color;
#else
varying lowp vec2 uv;
#define out_color gl_FragColor
#define texture texture2D
#endif
void main()
{
lowp vec4 col = vec4(0.0);
// Calculate the main rectangle distance field.
lowp float rect = sdf_rounded_rectangle(uv, aspect, radius);
// Sample the texture, then render it, without any alpha blending.
lowp vec2 texture_uv = ((uv / aspect) + 1.0) / 2.0;
lowp vec4 texture_color = vec4(texture(textureSource, texture_uv).rgb, 1.0);
col = sdf_render(rect, col, texture_color);
out_color = col * opacity;
}

View File

@ -1,67 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "shadowedborderrectanglematerial.h"
#include <QOpenGLContext>
QSGMaterialType ShadowedBorderRectangleMaterial::staticType;
ShadowedBorderRectangleMaterial::ShadowedBorderRectangleMaterial()
{
setFlag(QSGMaterial::Blending, true);
}
QSGMaterialShader* ShadowedBorderRectangleMaterial::createShader() const
{
return new ShadowedBorderRectangleShader{shaderType};
}
QSGMaterialType* ShadowedBorderRectangleMaterial::type() const
{
return &staticType;
}
int ShadowedBorderRectangleMaterial::compare(const QSGMaterial *other) const
{
auto material = static_cast<const ShadowedBorderRectangleMaterial *>(other);
auto result = ShadowedRectangleMaterial::compare(other);
if (result == 0
&& material->borderColor == borderColor
&& qFuzzyCompare(material->borderWidth, borderWidth)
) {
return 0;
}
return result;
}
ShadowedBorderRectangleShader::ShadowedBorderRectangleShader(ShadowedRectangleMaterial::ShaderType shaderType)
: ShadowedRectangleShader(shaderType)
{
setShader(shaderType, QStringLiteral("shadowedborderrectangle"));
}
void ShadowedBorderRectangleShader::initialize()
{
ShadowedRectangleShader::initialize();
m_borderWidthLocation = program()->uniformLocation("borderWidth");
m_borderColorLocation = program()->uniformLocation("borderColor");
}
void ShadowedBorderRectangleShader::updateState(const QSGMaterialShader::RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial)
{
ShadowedRectangleShader::updateState(state, newMaterial, oldMaterial);
auto p = program();
if (!oldMaterial || newMaterial->compare(oldMaterial) != 0 ) {
auto material = static_cast<ShadowedBorderRectangleMaterial *>(newMaterial);
p->setUniformValue(m_borderWidthLocation, material->borderWidth);
p->setUniformValue(m_borderColorLocation, material->borderColor);
}
}

View File

@ -1,43 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once
#include "shadowedrectanglematerial.h"
/**
* A material rendering a rectangle with a shadow and a border.
*
* This material uses a distance field shader to render a rectangle with a
* shadow below it, optionally with rounded corners and a border.
*/
class ShadowedBorderRectangleMaterial : public ShadowedRectangleMaterial
{
public:
ShadowedBorderRectangleMaterial();
QSGMaterialShader* createShader() const override;
QSGMaterialType* type() const override;
int compare(const QSGMaterial* other) const override;
float borderWidth = 0.0;
QColor borderColor = Qt::black;
static QSGMaterialType staticType;
};
class ShadowedBorderRectangleShader : public ShadowedRectangleShader
{
public:
ShadowedBorderRectangleShader(ShadowedRectangleMaterial::ShaderType shaderType);
void initialize() override;
void updateState(const QSGMaterialShader::RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
private:
int m_borderWidthLocation = -1;
int m_borderColorLocation = -1;
};

View File

@ -1,114 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "shadowedrectanglematerial.h"
#include <QOpenGLContext>
QSGMaterialType ShadowedRectangleMaterial::staticType;
ShadowedRectangleMaterial::ShadowedRectangleMaterial()
{
setFlag(QSGMaterial::Blending, true);
}
QSGMaterialShader* ShadowedRectangleMaterial::createShader() const
{
return new ShadowedRectangleShader{shaderType};
}
QSGMaterialType* ShadowedRectangleMaterial::type() const
{
return &staticType;
}
int ShadowedRectangleMaterial::compare(const QSGMaterial *other) const
{
auto material = static_cast<const ShadowedRectangleMaterial *>(other);
if (material->color == color
&& material->shadowColor == shadowColor
&& material->offset == offset
&& material->aspect == aspect
&& qFuzzyCompare(material->size, size)
&& qFuzzyCompare(material->radius, radius)) {
return 0;
}
return QSGMaterial::compare(other);
}
ShadowedRectangleShader::ShadowedRectangleShader(ShadowedRectangleMaterial::ShaderType shaderType)
{
setShader(shaderType, QStringLiteral("shadowedrectangle"));
}
const char *const * ShadowedRectangleShader::attributeNames() const
{
static char const *const names[] = {"in_vertex", "in_uv", nullptr};
return names;
}
void ShadowedRectangleShader::initialize()
{
QSGMaterialShader::initialize();
m_matrixLocation = program()->uniformLocation("matrix");
m_aspectLocation = program()->uniformLocation("aspect");
m_opacityLocation = program()->uniformLocation("opacity");
m_sizeLocation = program()->uniformLocation("size");
m_radiusLocation = program()->uniformLocation("radius");
m_colorLocation = program()->uniformLocation("color");
m_shadowColorLocation = program()->uniformLocation("shadowColor");
m_offsetLocation = program()->uniformLocation("offset");
}
void ShadowedRectangleShader::updateState(const QSGMaterialShader::RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial)
{
auto p = program();
if (state.isMatrixDirty()) {
p->setUniformValue(m_matrixLocation, state.combinedMatrix());
}
if (state.isOpacityDirty()) {
p->setUniformValue(m_opacityLocation, state.opacity());
}
if (!oldMaterial || newMaterial->compare(oldMaterial) != 0 ) {
auto material = static_cast<ShadowedRectangleMaterial *>(newMaterial);
p->setUniformValue(m_aspectLocation, material->aspect);
p->setUniformValue(m_sizeLocation, material->size);
p->setUniformValue(m_radiusLocation, material->radius);
p->setUniformValue(m_colorLocation, material->color);
p->setUniformValue(m_shadowColorLocation, material->shadowColor);
p->setUniformValue(m_offsetLocation, material->offset);
}
}
void ShadowedRectangleShader::setShader(ShadowedRectangleMaterial::ShaderType shaderType, const QString& shader)
{
auto header = QOpenGLContext::currentContext()->isOpenGLES() ? QStringLiteral("header_es.glsl") : QStringLiteral("header_desktop.glsl");
auto shaderRoot = QStringLiteral(":/org/kde/kirigami/shaders/");
setShaderSourceFiles(QOpenGLShader::Vertex, {
shaderRoot + header,
shaderRoot + QStringLiteral("shadowedrectangle.vert")
});
QString shaderFile = shader + QStringLiteral(".frag");
auto sdfFile = QStringLiteral("sdf.glsl");
if (shaderType == ShadowedRectangleMaterial::ShaderType::LowPower) {
shaderFile = shader + QStringLiteral("_lowpower.frag");
sdfFile = QStringLiteral("sdf_lowpower.glsl");
}
setShaderSourceFiles(QOpenGLShader::Fragment, {
shaderRoot + header,
shaderRoot + sdfFile,
shaderRoot + shaderFile
});
}

View File

@ -1,67 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once
#include <QSGMaterial>
#include <QSGMaterialShader>
#include <QColor>
/**
* A material rendering a rectangle with a shadow.
*
* This material uses a distance field shader to render a rectangle with a
* shadow below it, optionally with rounded corners.
*/
class ShadowedRectangleMaterial : public QSGMaterial
{
public:
enum class ShaderType
{
Standard,
LowPower
};
ShadowedRectangleMaterial();
QSGMaterialShader* createShader() const override;
QSGMaterialType* type() const override;
int compare( const QSGMaterial* other ) const override;
QVector2D aspect = QVector2D{1.0, 1.0};
float size = 0.0;
QVector4D radius = QVector4D{0.0, 0.0, 0.0, 0.0};
QColor color = Qt::white;
QColor shadowColor = Qt::black;
QVector2D offset;
ShaderType shaderType = ShaderType::Standard;
static QSGMaterialType staticType;
};
class ShadowedRectangleShader : public QSGMaterialShader
{
public:
ShadowedRectangleShader( ShadowedRectangleMaterial::ShaderType shaderType );
char const* const* attributeNames() const override;
void initialize() override;
void updateState( const QSGMaterialShader::RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial ) override;
protected:
void setShader( ShadowedRectangleMaterial::ShaderType shaderType, const QString& shader );
private:
int m_matrixLocation = -1;
int m_opacityLocation = -1;
int m_aspectLocation = -1;
int m_sizeLocation = -1;
int m_radiusLocation = -1;
int m_colorLocation = -1;
int m_shadowColorLocation = -1;
int m_offsetLocation = -1;
};

View File

@ -1,209 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "shadowedrectanglenode.h"
#include "shadowedrectanglematerial.h"
#include "shadowedborderrectanglematerial.h"
QColor premultiply(const QColor &color)
{
return QColor::fromRgbF(
color.redF() * color.alphaF(),
color.greenF() * color.alphaF(),
color.blueF() * color.alphaF(),
color.alphaF()
);
}
ShadowedRectangleNode::ShadowedRectangleNode()
{
m_geometry = new QSGGeometry{QSGGeometry::defaultAttributes_TexturedPoint2D(), 4};
setGeometry(m_geometry);
setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial);
}
void ShadowedRectangleNode::setBorderEnabled(bool enabled)
{
// We can achieve more performant shaders by splitting the two into separate
// shaders. This requires separating the materials as well. So when
// borderWidth is increased to something where the border should be visible,
// switch to the with-border material. Otherwise use the no-border version.
if (enabled) {
if (!m_material || m_material->type() == borderlessMaterialType()) {
auto newMaterial = createBorderMaterial();
newMaterial->shaderType = m_shaderType;
setMaterial(newMaterial);
m_material = newMaterial;
m_rect = QRectF{};
markDirty(QSGNode::DirtyMaterial);
}
} else {
if (!m_material || m_material->type() == borderMaterialType()) {
auto newMaterial = createBorderlessMaterial();
newMaterial->shaderType = m_shaderType;
setMaterial(newMaterial);
m_material = newMaterial;
m_rect = QRectF{};
markDirty(QSGNode::DirtyMaterial);
}
}
}
void ShadowedRectangleNode::setRect(const QRectF& rect)
{
if (rect == m_rect) {
return;
}
m_rect = rect;
QVector2D newAspect{1.0, 1.0};
if (m_rect.width() >= m_rect.height()) {
newAspect.setX(m_rect.width() / m_rect.height());
} else {
newAspect.setY(m_rect.height() / m_rect.width());
}
if (m_material->aspect != newAspect) {
m_material->aspect = newAspect;
markDirty(QSGNode::DirtyMaterial);
m_aspect = newAspect;
}
}
void ShadowedRectangleNode::setSize(qreal size)
{
auto minDimension = std::min(m_rect.width(), m_rect.height());
float uniformSize = (size / minDimension) * 2.0;
if (!qFuzzyCompare(m_material->size, uniformSize)) {
m_material->size = uniformSize;
markDirty(QSGNode::DirtyMaterial);
m_size = size;
}
}
void ShadowedRectangleNode::setRadius(const QVector4D &radius)
{
float minDimension = std::min(m_rect.width(), m_rect.height());
auto uniformRadius = QVector4D{
std::min(radius.x() * 2.0f / minDimension, 1.0f),
std::min(radius.y() * 2.0f / minDimension, 1.0f),
std::min(radius.z() * 2.0f / minDimension, 1.0f),
std::min(radius.w() * 2.0f / minDimension, 1.0f)
};
if (m_material->radius != uniformRadius) {
m_material->radius = uniformRadius;
markDirty(QSGNode::DirtyMaterial);
m_radius = radius;
}
}
void ShadowedRectangleNode::setColor(const QColor &color)
{
auto premultiplied = premultiply(color);
if (m_material->color != premultiplied) {
m_material->color = premultiplied;
markDirty(QSGNode::DirtyMaterial);
}
}
void ShadowedRectangleNode::setShadowColor(const QColor& color)
{
auto premultiplied = premultiply(color);
if (m_material->shadowColor != premultiplied) {
m_material->shadowColor = premultiplied;
markDirty(QSGNode::DirtyMaterial);
}
}
void ShadowedRectangleNode::setOffset(const QVector2D& offset)
{
auto minDimension = std::min(m_rect.width(), m_rect.height());
auto uniformOffset = offset / minDimension;
if (m_material->offset != uniformOffset) {
m_material->offset = uniformOffset;
markDirty(QSGNode::DirtyMaterial);
m_offset = offset;
}
}
void ShadowedRectangleNode::setBorderWidth(qreal width)
{
if (m_material->type() != borderMaterialType()) {
return;
}
auto minDimension = std::min(m_rect.width(), m_rect.height());
float uniformBorderWidth = width / minDimension;
auto borderMaterial = static_cast<ShadowedBorderRectangleMaterial*>(m_material);
if (!qFuzzyCompare(borderMaterial->borderWidth, uniformBorderWidth)) {
borderMaterial->borderWidth = uniformBorderWidth;
markDirty(QSGNode::DirtyMaterial);
m_borderWidth = width;
}
}
void ShadowedRectangleNode::setBorderColor(const QColor& color)
{
if (m_material->type() != borderMaterialType()) {
return;
}
auto borderMaterial = static_cast<ShadowedBorderRectangleMaterial*>(m_material);
auto premultiplied = premultiply(color);
if (borderMaterial->borderColor != premultiplied) {
borderMaterial->borderColor = premultiplied;
markDirty(QSGNode::DirtyMaterial);
}
}
void ShadowedRectangleNode::setShaderType(ShadowedRectangleMaterial::ShaderType type)
{
m_shaderType = type;
}
void ShadowedRectangleNode::updateGeometry()
{
auto rect = m_rect;
if (m_shaderType == ShadowedRectangleMaterial::ShaderType::Standard) {
rect = rect.adjusted(-m_size * m_aspect.x(), -m_size * m_aspect.y(),
m_size * m_aspect.x(), m_size * m_aspect.y());
auto offsetLength = m_offset.length();
rect = rect.adjusted(-offsetLength * m_aspect.x(), -offsetLength * m_aspect.y(),
offsetLength * m_aspect.x(), offsetLength * m_aspect.y());
}
QSGGeometry::updateTexturedRectGeometry(m_geometry, rect, QRectF{0.0, 0.0, 1.0, 1.0});
markDirty(QSGNode::DirtyGeometry);
}
ShadowedRectangleMaterial *ShadowedRectangleNode::createBorderlessMaterial()
{
return new ShadowedRectangleMaterial{};
}
ShadowedBorderRectangleMaterial *ShadowedRectangleNode::createBorderMaterial()
{
return new ShadowedBorderRectangleMaterial{};
}
QSGMaterialType *ShadowedRectangleNode::borderlessMaterialType()
{
return &ShadowedRectangleMaterial::staticType;
}
QSGMaterialType *ShadowedRectangleNode::borderMaterialType()
{
return &ShadowedBorderRectangleMaterial::staticType;
}

View File

@ -1,79 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once
#include <QSGGeometryNode>
#include <QColor>
#include <QVector2D>
#include <QVector4D>
#include "shadowedrectanglematerial.h"
struct QSGMaterialType;
class ShadowedBorderRectangleMaterial;
/**
* Scene graph node for a shadowed rectangle.
*
* This node will set up the geometry and materials for a shadowed rectangle,
* optionally with rounded corners.
*
* \note You must call updateGeometry() after setting properties of this node,
* otherwise the node's state will not correctly reflect all the properties.
*
* \sa ShadowedRectangle
*/
class ShadowedRectangleNode : public QSGGeometryNode
{
public:
ShadowedRectangleNode();
/**
* Set whether to draw a border.
*
* Note that this will switch between a material with or without border.
* This means this needs to be called before any other setters.
*/
void setBorderEnabled(bool enabled);
void setRect(const QRectF &rect);
void setSize(qreal size);
void setRadius(const QVector4D &radius);
void setColor(const QColor &color);
void setShadowColor(const QColor &color);
void setOffset(const QVector2D &offset);
void setBorderWidth(qreal width);
void setBorderColor(const QColor &color);
void setShaderType(ShadowedRectangleMaterial::ShaderType type);
/**
* Update the geometry for this node.
*
* This is done as an explicit step to avoid the geometry being recreated
* multiple times while updating properties.
*/
void updateGeometry();
protected:
virtual ShadowedRectangleMaterial *createBorderlessMaterial();
virtual ShadowedBorderRectangleMaterial *createBorderMaterial();
virtual QSGMaterialType* borderMaterialType();
virtual QSGMaterialType* borderlessMaterialType();
QSGGeometry *m_geometry;
ShadowedRectangleMaterial *m_material = nullptr;
ShadowedRectangleMaterial::ShaderType m_shaderType = ShadowedRectangleMaterial::ShaderType::Standard;
private:
QRectF m_rect;
qreal m_size = 0.0;
QVector4D m_radius = QVector4D{0.0, 0.0, 0.0, 0.0};
QVector2D m_offset = QVector2D{0.0, 0.0};
QVector2D m_aspect = QVector2D{1.0, 1.0};
qreal m_borderWidth = 0.0;
QColor m_borderColor;
};

View File

@ -1,368 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "shadowedrectangle.h"
#include <QQuickWindow>
#include "scenegraph/shadowedrectanglenode.h"
#include "scenegraph/paintedrectangleitem.h"
BorderGroup::BorderGroup( QObject* parent )
: QObject( parent )
{
}
qreal BorderGroup::width() const
{
return m_width;
}
void BorderGroup::setWidth( qreal newWidth )
{
if( newWidth == m_width )
{
return;
}
m_width = newWidth;
Q_EMIT changed();
}
QColor BorderGroup::color() const
{
return m_color;
}
void BorderGroup::setColor( const QColor& newColor )
{
if( newColor == m_color )
{
return;
}
m_color = newColor;
Q_EMIT changed();
}
ShadowGroup::ShadowGroup( QObject* parent )
: QObject( parent )
{
}
qreal ShadowGroup::size() const
{
return m_size;
}
void ShadowGroup::setSize( qreal newSize )
{
if( newSize == m_size )
{
return;
}
m_size = newSize;
Q_EMIT changed();
}
qreal ShadowGroup::xOffset() const
{
return m_xOffset;
}
void ShadowGroup::setXOffset( qreal newXOffset )
{
if( newXOffset == m_xOffset )
{
return;
}
m_xOffset = newXOffset;
Q_EMIT changed();
}
qreal ShadowGroup::yOffset() const
{
return m_yOffset;
}
void ShadowGroup::setYOffset( qreal newYOffset )
{
if( newYOffset == m_yOffset )
{
return;
}
m_yOffset = newYOffset;
Q_EMIT changed();
}
QColor ShadowGroup::color() const
{
return m_color;
}
void ShadowGroup::setColor( const QColor& newColor )
{
if( newColor == m_color )
{
return;
}
m_color = newColor;
Q_EMIT changed();
}
CornersGroup::CornersGroup( QObject* parent )
: QObject( parent )
{
}
qreal CornersGroup::topLeft() const
{
return m_topLeft;
}
void CornersGroup::setTopLeft( qreal newTopLeft )
{
if( newTopLeft == m_topLeft )
{
return;
}
m_topLeft = newTopLeft;
Q_EMIT changed();
}
qreal CornersGroup::topRight() const
{
return m_topRight;
}
void CornersGroup::setTopRight( qreal newTopRight )
{
if( newTopRight == m_topRight )
{
return;
}
m_topRight = newTopRight;
Q_EMIT changed();
}
qreal CornersGroup::bottomLeft() const
{
return m_bottomLeft;
}
void CornersGroup::setBottomLeft( qreal newBottomLeft )
{
if( newBottomLeft == m_bottomLeft )
{
return;
}
m_bottomLeft = newBottomLeft;
Q_EMIT changed();
}
qreal CornersGroup::bottomRight() const
{
return m_bottomRight;
}
void CornersGroup::setBottomRight( qreal newBottomRight )
{
if( newBottomRight == m_bottomRight )
{
return;
}
m_bottomRight = newBottomRight;
Q_EMIT changed();
}
QVector4D CornersGroup::toVector4D( float all ) const
{
return QVector4D
{
m_bottomRight < 0.0 ? all : m_bottomRight,
m_topRight < 0.0 ? all : m_topRight,
m_bottomLeft < 0.0 ? all : m_bottomLeft,
m_topLeft < 0.0 ? all : m_topLeft
};
}
ShadowedRectangle::ShadowedRectangle( QQuickItem* parentItem )
: QQuickItem( parentItem )
, m_border( new BorderGroup )
, m_shadow( new ShadowGroup )
, m_corners( new CornersGroup )
{
setFlag( QQuickItem::ItemHasContents, true );
connect( m_border.get(), &BorderGroup::changed, this, &ShadowedRectangle::update );
connect( m_shadow.get(), &ShadowGroup::changed, this, &ShadowedRectangle::update );
connect( m_corners.get(), &CornersGroup::changed, this, &ShadowedRectangle::update );
}
ShadowedRectangle::~ShadowedRectangle()
{
}
BorderGroup* ShadowedRectangle::border() const
{
return m_border.get();
}
ShadowGroup* ShadowedRectangle::shadow() const
{
return m_shadow.get();
}
CornersGroup* ShadowedRectangle::corners() const
{
return m_corners.get();
}
qreal ShadowedRectangle::radius() const
{
return m_radius;
}
void ShadowedRectangle::setRadius( qreal newRadius )
{
if( newRadius == m_radius )
{
return;
}
m_radius = newRadius;
if( !isSoftwareRendering() )
{
update();
}
Q_EMIT radiusChanged();
}
QColor ShadowedRectangle::color() const
{
return m_color;
}
void ShadowedRectangle::setColor( const QColor& newColor )
{
if( newColor == m_color )
{
return;
}
m_color = newColor;
if( !isSoftwareRendering() )
{
update();
}
Q_EMIT colorChanged();
}
void ShadowedRectangle::componentComplete()
{
QQuickItem::componentComplete();
checkSoftwareItem();
}
bool ShadowedRectangle::isSoftwareRendering() const
{
return false;
}
PaintedRectangleItem* ShadowedRectangle::softwareItem() const
{
return m_softwareItem;
}
void ShadowedRectangle::itemChange( QQuickItem::ItemChange change, const QQuickItem::ItemChangeData& value )
{
if( change == QQuickItem::ItemSceneChange && value.window )
{
checkSoftwareItem();
//TODO: only conditionally emit?
Q_EMIT softwareRenderingChanged();
}
}
QSGNode* ShadowedRectangle::updatePaintNode( QSGNode* node, QQuickItem::UpdatePaintNodeData* data )
{
Q_UNUSED( data );
auto shadowNode = static_cast<ShadowedRectangleNode*>( node );
if( !shadowNode )
{
shadowNode = new ShadowedRectangleNode{};
// Cache lowPower state so we only execute the full check once.
static bool lowPower = QByteArrayList{"1", "true"}.contains( qgetenv( "KIRIGAMI_LOWPOWER_HARDWARE" ).toLower() );
if( lowPower )
{
shadowNode->setShaderType( ShadowedRectangleMaterial::ShaderType::LowPower );
}
}
shadowNode->setBorderEnabled( m_border->isEnabled() );
shadowNode->setRect( boundingRect() );
shadowNode->setSize( m_shadow->size() );
shadowNode->setRadius( m_corners->toVector4D( m_radius ) );
shadowNode->setOffset( QVector2D{float( m_shadow->xOffset() ), float( m_shadow->yOffset() )} );
shadowNode->setColor( m_color );
shadowNode->setShadowColor( m_shadow->color() );
shadowNode->setBorderWidth( m_border->width() );
shadowNode->setBorderColor( m_border->color() );
shadowNode->updateGeometry();
return shadowNode;
}
void ShadowedRectangle::checkSoftwareItem()
{
if( !m_softwareItem && isSoftwareRendering() )
{
m_softwareItem = new PaintedRectangleItem{this};
// The software item is added as a "normal" child item, this means it
// will be part of the normal item sort order. Since there is no way to
// control the ordering of children, just make sure to have a very low Z
// value for the child, to force it to be the lowest item.
m_softwareItem->setZ( -99.0 );
auto updateItem = [this]()
{
auto borderWidth = m_border->width();
auto rect = boundingRect().adjusted( -borderWidth / 2, -borderWidth / 2, borderWidth / 2, borderWidth / 2 );
m_softwareItem->setX( -borderWidth / 2 );
m_softwareItem->setY( -borderWidth / 2 );
m_softwareItem->setSize( rect.size() );
m_softwareItem->setColor( m_color );
m_softwareItem->setRadius( m_radius );
m_softwareItem->setBorderWidth( borderWidth );
m_softwareItem->setBorderColor( m_border->color() );
};
updateItem();
connect( this, &ShadowedRectangle::widthChanged, m_softwareItem, updateItem );
connect( this, &ShadowedRectangle::heightChanged, m_softwareItem, updateItem );
connect( this, &ShadowedRectangle::colorChanged, m_softwareItem, updateItem );
connect( this, &ShadowedRectangle::radiusChanged, m_softwareItem, updateItem );
connect( m_border.get(), &BorderGroup::changed, m_softwareItem, updateItem );
setFlag( QQuickItem::ItemHasContents, false );
}
}

View File

@ -1,256 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once
#include <memory>
#include <QQuickItem>
class PaintedRectangleItem;
/**
* Grouped property for rectangle border.
*/
class BorderGroup : public QObject
{
Q_OBJECT
/**
* The width of the border in pixels.
*
* Default is 0.
*/
Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY changed)
/**
* The color of the border.
*
* Full RGBA colors are supported. The default is fully opaque black.
*/
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed)
public:
explicit BorderGroup(QObject *parent = nullptr);
qreal width() const;
void setWidth(qreal newWidth);
QColor color() const;
void setColor(const QColor &newColor);
Q_SIGNAL void changed();
inline bool isEnabled() const
{
return !qFuzzyIsNull(m_width);
}
private:
qreal m_width = 0.0;
QColor m_color = Qt::black;
};
/**
* Grouped property for rectangle shadow.
*/
class ShadowGroup : public QObject
{
Q_OBJECT
/**
* The size of the shadow.
*
* This is the approximate size of the shadow in pixels. However, due to falloff
* the actual shadow size can differ. The default is 0, which means no shadow will
* be rendered.
*/
Q_PROPERTY(qreal size READ size WRITE setSize NOTIFY changed)
/**
* Offset of the shadow on the X axis.
*
* In pixels. The default is 0.
*/
Q_PROPERTY(qreal xOffset READ xOffset WRITE setXOffset NOTIFY changed)
/**
* Offset of the shadow on the Y axis.
*
* In pixels. The default is 0.
*/
Q_PROPERTY(qreal yOffset READ yOffset WRITE setYOffset NOTIFY changed)
/**
* The color of the shadow.
*
* Full RGBA colors are supported. The default is fully opaque black.
*/
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed)
public:
explicit ShadowGroup(QObject *parent = nullptr);
qreal size() const;
void setSize(qreal newSize);
qreal xOffset() const;
void setXOffset(qreal newXOffset);
qreal yOffset() const;
void setYOffset(qreal newYOffset);
QColor color() const;
void setColor(const QColor &newShadowColor);
Q_SIGNAL void changed();
private:
qreal m_size = 0.0;
qreal m_xOffset = 0.0;
qreal m_yOffset = 0.0;
QColor m_color = Qt::black;
};
/**
* Grouped property for corner radius.
*/
class CornersGroup : public QObject
{
Q_OBJECT
/**
* The radius of the top-left corner.
*
* In pixels. Defaults to -1, which indicates this value should not be used.
*/
Q_PROPERTY(qreal topLeftRadius READ topLeft WRITE setTopLeft NOTIFY changed)
/**
* The radius of the top-right corner.
*
* In pixels. Defaults to -1, which indicates this value should not be used.
*/
Q_PROPERTY(qreal topRightRadius READ topRight WRITE setTopRight NOTIFY changed)
/**
* The radius of the bottom-left corner.
*
* In pixels. Defaults to -1, which indicates this value should not be used.
*/
Q_PROPERTY(qreal bottomLeftRadius READ bottomLeft WRITE setBottomLeft NOTIFY changed)
/**
* The radius of the bottom-right corner.
*
* In pixels. Defaults to -1, which indicates this value should not be used.
*/
Q_PROPERTY(qreal bottomRightRadius READ bottomRight WRITE setBottomRight NOTIFY changed)
public:
explicit CornersGroup(QObject *parent = nullptr);
qreal topLeft() const;
void setTopLeft(qreal newTopLeft);
qreal topRight() const;
void setTopRight(qreal newTopRight);
qreal bottomLeft() const;
void setBottomLeft(qreal newBottomLeft);
qreal bottomRight() const;
void setBottomRight(qreal newBottomRight);
Q_SIGNAL void changed();
QVector4D toVector4D(float all) const;
private:
float m_topLeft = -1.0;
float m_topRight = -1.0;
float m_bottomLeft = -1.0;
float m_bottomRight = -1.0;
};
/**
* A rectangle with a shadow.
*
* This item will render a rectangle, with a shadow below it. The rendering is done
* using distance fields, which provide greatly improved performance. The shadow is
* rendered outside of the item's bounds, so the item's width and height are the
* rectangle's width and height.
*
* @since 5.69 / 2.12
*/
class ShadowedRectangle : public QQuickItem
{
Q_OBJECT
/**
* Corner radius of the rectangle.
*
* This is the amount of rounding to apply to all of the rectangle's
* corners, in pixels. Individual corners can have a different radius, see
* \property corners.
*
* The default is 0.
*/
Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
/**
* The color of the rectangle.
*
* Full RGBA colors are supported. The default is fully opaque white.
*/
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
/**
* Border properties.
*
* \sa BorderGroup
*/
Q_PROPERTY(BorderGroup *border READ border CONSTANT)
/**
* Shadow properties.
*
* \sa ShadowGroup
*/
Q_PROPERTY(ShadowGroup *shadow READ shadow CONSTANT)
/**
* Corner radius.
*
* Note that the values from this group override \property radius for the
* corner they affect.
*
* \sa CornerGroup
*/
Q_PROPERTY(CornersGroup *corners READ corners CONSTANT)
Q_PROPERTY(bool softwareRendering READ isSoftwareRendering NOTIFY softwareRenderingChanged)
public:
ShadowedRectangle(QQuickItem *parent = nullptr);
~ShadowedRectangle() override;
BorderGroup *border() const;
ShadowGroup *shadow() const;
CornersGroup *corners() const;
qreal radius() const;
void setRadius(qreal newRadius);
Q_SIGNAL void radiusChanged();
QColor color() const;
void setColor(const QColor &newColor);
Q_SIGNAL void colorChanged();
void componentComplete() override;
bool isSoftwareRendering() const;
Q_SIGNALS:
void softwareRenderingChanged();
protected:
PaintedRectangleItem *softwareItem() const;
void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) override;
QSGNode *updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *data) override;
private:
void checkSoftwareItem();
const std::unique_ptr<BorderGroup> m_border;
const std::unique_ptr<ShadowGroup> m_shadow;
const std::unique_ptr<CornersGroup> m_corners;
qreal m_radius = 0.0;
QColor m_color = Qt::white;
PaintedRectangleItem *m_softwareItem = nullptr;
};