proof of concept for #220
This commit is contained in:
parent
320a62ae4b
commit
b91e788639
|
@ -0,0 +1,114 @@
|
||||||
|
#include "BlurredBox.h"
|
||||||
|
#include "BlurredBoxSkinlet.h"
|
||||||
|
|
||||||
|
#include <QQuickWindow>
|
||||||
|
|
||||||
|
QSK_SUBCONTROL( BlurredBox, Panel )
|
||||||
|
|
||||||
|
class BlurredBoxSkinlet;
|
||||||
|
|
||||||
|
BlurredBox::BlurredBox( QQuickItem* parentItem )
|
||||||
|
: QskBox( parentItem )
|
||||||
|
{
|
||||||
|
setFlag( QQuickItem::ItemHasContents, true );
|
||||||
|
setSkinlet( new BlurredBoxSkinlet() );
|
||||||
|
setPolishOnResize( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
BlurredBox::~BlurredBox() = default;
|
||||||
|
|
||||||
|
void BlurredBox::setShape( const QskBoxShapeMetrics& shape )
|
||||||
|
{
|
||||||
|
m_shape = shape;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QskBoxShapeMetrics& BlurredBox::shape() const
|
||||||
|
{
|
||||||
|
return m_shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF BlurredBox::rectOnScreen() const
|
||||||
|
{
|
||||||
|
return mapRectToScene( contentsRect() );
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF BlurredBox::rectOfScreen() const
|
||||||
|
{
|
||||||
|
// find root node and get its rectangle
|
||||||
|
auto* root = parentItem();
|
||||||
|
|
||||||
|
while ( root && root->parentItem() )
|
||||||
|
{
|
||||||
|
root = root->parentItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto rootRect = this->window()->contentItem()->boundingRect();
|
||||||
|
return rootRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlurredBox::geometryChangeEvent( QskGeometryChangeEvent* e )
|
||||||
|
{
|
||||||
|
Inherited::geometryChangeEvent( e );
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF BlurredBox::layoutRectForSize( const QSizeF& size ) const
|
||||||
|
{
|
||||||
|
auto padding = paddingHint( Panel );
|
||||||
|
return { padding.left() / 2, padding.top() / 2, size.width() - padding.right(),
|
||||||
|
size.height() - padding.bottom() };
|
||||||
|
}
|
||||||
|
|
||||||
|
float BlurredBox::blurDirections() const
|
||||||
|
{
|
||||||
|
return m_blurDirections;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlurredBox::setBlurDirections( float newBlurDirections )
|
||||||
|
{
|
||||||
|
if ( qFuzzyCompare( m_blurDirections, newBlurDirections ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_blurDirections = newBlurDirections;
|
||||||
|
update();
|
||||||
|
Q_EMIT blurDirectionsChanged( m_blurDirections );
|
||||||
|
}
|
||||||
|
|
||||||
|
float BlurredBox::blurQuality() const
|
||||||
|
{
|
||||||
|
return m_blurQuality;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlurredBox::setBlurQuality( float newBlurQuality )
|
||||||
|
{
|
||||||
|
if ( qFuzzyCompare( m_blurQuality, newBlurQuality ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_blurQuality = newBlurQuality;
|
||||||
|
update();
|
||||||
|
Q_EMIT blurQualityChanged( m_blurQuality );
|
||||||
|
}
|
||||||
|
|
||||||
|
float BlurredBox::blurSize() const
|
||||||
|
{
|
||||||
|
return m_blurSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlurredBox::setBlurSize( float newBlurSize )
|
||||||
|
{
|
||||||
|
if ( qFuzzyCompare( m_blurSize, newBlurSize ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_blurSize = newBlurSize;
|
||||||
|
update();
|
||||||
|
Q_EMIT blurSizeChanged( m_blurSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_BlurredBox.cpp"
|
|
@ -0,0 +1,55 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QskBox.h>
|
||||||
|
#include <QskBoxShapeMetrics.h>
|
||||||
|
#include <QskShadowMetrics.h>
|
||||||
|
|
||||||
|
class QskGradient;
|
||||||
|
|
||||||
|
class BlurredBox : public QskBox
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY( float blurDirections READ blurDirections WRITE setBlurDirections NOTIFY
|
||||||
|
blurDirectionsChanged )
|
||||||
|
Q_PROPERTY( float blurQuality READ blurQuality WRITE setBlurQuality NOTIFY blurQualityChanged )
|
||||||
|
Q_PROPERTY( float blurSize READ blurSize WRITE setBlurSize NOTIFY blurSizeChanged )
|
||||||
|
using Inherited = QskBox;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QSK_SUBCONTROLS( Panel )
|
||||||
|
|
||||||
|
BlurredBox( QQuickItem* parent = nullptr );
|
||||||
|
~BlurredBox() override;
|
||||||
|
|
||||||
|
QRectF layoutRectForSize( const QSizeF& size ) const override;
|
||||||
|
|
||||||
|
void setShape( const QskBoxShapeMetrics& );
|
||||||
|
const QskBoxShapeMetrics& shape() const;
|
||||||
|
|
||||||
|
QRectF rectOnScreen() const;
|
||||||
|
QRectF rectOfScreen() const;
|
||||||
|
|
||||||
|
void geometryChangeEvent( QskGeometryChangeEvent* ) override;
|
||||||
|
|
||||||
|
float blurDirections() const;
|
||||||
|
void setBlurDirections( float newBlurDirections );
|
||||||
|
|
||||||
|
float blurQuality() const;
|
||||||
|
void setBlurQuality( float newBlurQuality );
|
||||||
|
|
||||||
|
float blurSize() const;
|
||||||
|
void setBlurSize( float newBlurSize );
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void blurDirectionsChanged( float );
|
||||||
|
void blurQualityChanged( float );
|
||||||
|
void blurSizeChanged( float );
|
||||||
|
|
||||||
|
private:
|
||||||
|
QskBoxShapeMetrics m_shape;
|
||||||
|
qreal m_borderWidth = 0.0;
|
||||||
|
QColor m_borderColor = Qt::black;
|
||||||
|
float m_blurDirections = 32.0;
|
||||||
|
float m_blurQuality = 8.0;
|
||||||
|
float m_blurSize = 8.0;
|
||||||
|
};
|
|
@ -0,0 +1,34 @@
|
||||||
|
#include "BlurredBoxMaterial.h"
|
||||||
|
#include "BlurredBoxMaterialShader.h"
|
||||||
|
|
||||||
|
BlurredBoxMaterial::BlurredBoxMaterial()
|
||||||
|
{
|
||||||
|
setFlag( QSGMaterial::Blending, true );
|
||||||
|
setFlag( QSGMaterial::SupportsRhiShader, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGMaterialShader* BlurredBoxMaterial::createShader() const
|
||||||
|
{
|
||||||
|
return new BlurredBoxMaterialShader();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGMaterialType* BlurredBoxMaterial::type() const
|
||||||
|
{
|
||||||
|
static QSGMaterialType staticType;
|
||||||
|
return &staticType;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BlurredBoxMaterial::compare( const QSGMaterial* other ) const
|
||||||
|
{
|
||||||
|
auto material = dynamic_cast< const BlurredBoxMaterial* >( other );
|
||||||
|
|
||||||
|
if ( material->m_rectOfScreen != m_rectOfScreen || material->m_rectOnScreen != m_rectOnScreen ||
|
||||||
|
!qFuzzyCompare( material->m_rectCornerRadii, m_rectCornerRadii ) ||
|
||||||
|
material->m_opacity != m_opacity || material->m_blurDirections != m_blurDirections ||
|
||||||
|
material->m_blurQuality != m_blurQuality || material->m_blurSize != m_blurSize )
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QSGMaterial::compare( other );
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QSGMaterial>
|
||||||
|
|
||||||
|
class BlurredBoxMaterial final : public QSGMaterial
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BlurredBoxMaterial();
|
||||||
|
|
||||||
|
QSGMaterialShader* createShader() const override;
|
||||||
|
QSGMaterialType* type() const override;
|
||||||
|
|
||||||
|
int compare( const QSGMaterial* other ) const override;
|
||||||
|
|
||||||
|
QVector4D m_rectOfScreen{ 0, 0, 0, 0 };
|
||||||
|
QVector4D m_rectOnScreen{ 0, 0, 0, 0 };
|
||||||
|
QVector4D m_rectCornerRadii{ 0, 0, 0, 0 };
|
||||||
|
float m_opacity = 1.0;
|
||||||
|
float m_blurDirections = 32.0;
|
||||||
|
float m_blurQuality = 8.0;
|
||||||
|
float m_blurSize = 8.0;
|
||||||
|
};
|
|
@ -0,0 +1,62 @@
|
||||||
|
#include "BlurredBoxMaterialShader.h"
|
||||||
|
#include "BlurredBoxMaterial.h"
|
||||||
|
|
||||||
|
BlurredBoxMaterialShader::BlurredBoxMaterialShader()
|
||||||
|
{
|
||||||
|
setShaderSourceFile( QOpenGLShader::Vertex, ":/shaders/blurredbox.vert" );
|
||||||
|
setShaderSourceFile( QOpenGLShader::Fragment, ":/shaders/blurredbox.frag" );
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const* BlurredBoxMaterialShader::attributeNames() const
|
||||||
|
{
|
||||||
|
static char const* const names[] = { "in_vertex", "in_coord", nullptr };
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlurredBoxMaterialShader::initialize()
|
||||||
|
{
|
||||||
|
QSGMaterialShader::initialize();
|
||||||
|
|
||||||
|
auto p = program();
|
||||||
|
|
||||||
|
m_matrixId = p->uniformLocation( "matrix" );
|
||||||
|
m_rectOpacityId = p->uniformLocation( "rectOpacity" );
|
||||||
|
m_rectCornerRadiiId = p->uniformLocation( "rectCornerRadii" );
|
||||||
|
m_blurDirectionsId = p->uniformLocation( "blurDirections" );
|
||||||
|
m_blurQualityId = p->uniformLocation( "blurQuality" );
|
||||||
|
m_rectOnScreen = p->uniformLocation( "rectOnScreen" );
|
||||||
|
m_rectOfScreen = p->uniformLocation( "rectOfScreen" );
|
||||||
|
m_blurSizeId = p->uniformLocation( "blurSize" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlurredBoxMaterialShader::updateState(
|
||||||
|
const RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial )
|
||||||
|
{
|
||||||
|
auto p = program();
|
||||||
|
|
||||||
|
if ( state.isMatrixDirty() )
|
||||||
|
{
|
||||||
|
p->setUniformValue( m_matrixId, state.combinedMatrix() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( state.isOpacityDirty() )
|
||||||
|
{
|
||||||
|
p->setUniformValue( m_rectOpacityId, state.opacity() );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool updateMaterial = ( oldMaterial == nullptr ) || newMaterial->compare( oldMaterial ) != 0;
|
||||||
|
|
||||||
|
updateMaterial |= state.isCachedMaterialDataDirty();
|
||||||
|
|
||||||
|
if ( updateMaterial )
|
||||||
|
{
|
||||||
|
auto material = dynamic_cast< const BlurredBoxMaterial* >( newMaterial );
|
||||||
|
|
||||||
|
p->setUniformValue( m_rectCornerRadiiId, material->m_rectCornerRadii );
|
||||||
|
p->setUniformValue( m_rectOfScreen, material->m_rectOfScreen );
|
||||||
|
p->setUniformValue( m_rectOnScreen, material->m_rectOnScreen );
|
||||||
|
p->setUniformValue( m_blurDirectionsId, material->m_blurDirections );
|
||||||
|
p->setUniformValue( m_blurQualityId, material->m_blurQuality );
|
||||||
|
p->setUniformValue( m_blurSizeId, material->m_blurSize );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QSGMaterialShader>
|
||||||
|
|
||||||
|
class BlurredBoxMaterialShader final : public QSGMaterialShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BlurredBoxMaterialShader();
|
||||||
|
char const* const* attributeNames() const override;
|
||||||
|
void initialize() override;
|
||||||
|
void updateState( const QSGMaterialShader::RenderState& state, QSGMaterial* newMaterial,
|
||||||
|
QSGMaterial* oldMaterial ) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_matrixId = -1;
|
||||||
|
int m_rectOpacityId = -1;
|
||||||
|
int m_rectCornerRadiiId = -1;
|
||||||
|
int m_rectOfScreen = -1;
|
||||||
|
int m_rectOnScreen = -1;
|
||||||
|
int m_blurDirectionsId = -1;
|
||||||
|
int m_blurQualityId = -1;
|
||||||
|
int m_blurSizeId = -1;
|
||||||
|
};
|
|
@ -0,0 +1,74 @@
|
||||||
|
#include "BlurredBoxNode.h"
|
||||||
|
#include "BlurredBoxMaterial.h"
|
||||||
|
|
||||||
|
#include <QskBoxShapeMetrics.h>
|
||||||
|
|
||||||
|
#include <qcolor.h>
|
||||||
|
#include <qsgmaterial.h>
|
||||||
|
#include <qsgmaterialshader.h>
|
||||||
|
|
||||||
|
QSK_QT_PRIVATE_BEGIN
|
||||||
|
#include <private/qsgnode_p.h>
|
||||||
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
|
class BlurredBoxNodePrivate final : public QSGGeometryNodePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BlurredBoxNodePrivate()
|
||||||
|
: geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGGeometry geometry;
|
||||||
|
BlurredBoxMaterial material;
|
||||||
|
QRectF rect;
|
||||||
|
};
|
||||||
|
|
||||||
|
BlurredBoxNode::BlurredBoxNode()
|
||||||
|
: QSGGeometryNode( *new BlurredBoxNodePrivate )
|
||||||
|
{
|
||||||
|
Q_D( BlurredBoxNode );
|
||||||
|
|
||||||
|
setGeometry( &d->geometry );
|
||||||
|
setMaterial( &d->material );
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlurredBoxNode::setBlurData( const QRectF& rect, const QskBoxShapeMetrics& shape,
|
||||||
|
const QRectF& rectOfScreen, const QRectF& rectOnScreen, float opacity, float blurDirections,
|
||||||
|
float blurQuality, float blurSize )
|
||||||
|
{
|
||||||
|
Q_D( BlurredBoxNode );
|
||||||
|
|
||||||
|
d->rect = rect;
|
||||||
|
|
||||||
|
const QRectF textureRect{ rectOnScreen.x() / rectOfScreen.width(),
|
||||||
|
rectOnScreen.y() / rectOfScreen.height(), rectOnScreen.width() / rectOfScreen.width(),
|
||||||
|
rectOnScreen.height() / rectOfScreen.height() };
|
||||||
|
|
||||||
|
QSGGeometry::updateTexturedRectGeometry( &d->geometry, d->rect, textureRect );
|
||||||
|
|
||||||
|
// update screen rectangle
|
||||||
|
d->material.m_rectOfScreen = { static_cast< float >( rectOfScreen.x() ),
|
||||||
|
static_cast< float >( rectOfScreen.y() ), static_cast< float >( rectOfScreen.width() ),
|
||||||
|
static_cast< float >( rectOfScreen.height() ) };
|
||||||
|
|
||||||
|
// update rectangle on screen
|
||||||
|
d->material.m_rectOnScreen = { static_cast< float >( rectOnScreen.x() ),
|
||||||
|
static_cast< float >( rectOnScreen.y() ), static_cast< float >( rectOnScreen.width() ),
|
||||||
|
static_cast< float >( rectOnScreen.height() ) };
|
||||||
|
|
||||||
|
// update all four corner radii
|
||||||
|
d->material.m_rectCornerRadii = { static_cast< float >(
|
||||||
|
shape.radius( Qt::TopLeftCorner ).width() ),
|
||||||
|
static_cast< float >( shape.radius( Qt::TopRightCorner ).width() ),
|
||||||
|
static_cast< float >( shape.radius( Qt::BottomRightCorner ).width() ),
|
||||||
|
static_cast< float >( shape.radius( Qt::BottomLeftCorner ).width() ) };
|
||||||
|
|
||||||
|
d->material.m_opacity = opacity;
|
||||||
|
d->material.m_blurDirections = blurDirections;
|
||||||
|
d->material.m_blurQuality = blurQuality;
|
||||||
|
d->material.m_blurSize = blurSize;
|
||||||
|
|
||||||
|
markDirty( QSGNode::DirtyGeometry );
|
||||||
|
markDirty( QSGNode::DirtyMaterial );
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QSGGeometryNode>
|
||||||
|
|
||||||
|
class QColor;
|
||||||
|
class QskBoxShapeMetrics;
|
||||||
|
|
||||||
|
class BlurredBoxNodePrivate;
|
||||||
|
|
||||||
|
class BlurredBoxNode : public QSGGeometryNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BlurredBoxNode();
|
||||||
|
|
||||||
|
void setBlurData( const QRectF&, const QskBoxShapeMetrics&, const QRectF& rectOfScreen,
|
||||||
|
const QRectF& rectOnScreen, float opacity, float blurDirections, float blurQuality,
|
||||||
|
float blurSize );
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DECLARE_PRIVATE( BlurredBoxNode )
|
||||||
|
};
|
|
@ -0,0 +1,43 @@
|
||||||
|
#include "BlurredBoxSkinlet.h"
|
||||||
|
#include "BlurredBox.h"
|
||||||
|
#include "BlurredBoxNode.h"
|
||||||
|
|
||||||
|
BlurredBoxSkinlet::BlurredBoxSkinlet()
|
||||||
|
{
|
||||||
|
setOwnedBySkinnable( true );
|
||||||
|
setNodeRoles( { PanelRole } );
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF BlurredBoxSkinlet::subControlRect(
|
||||||
|
const QskSkinnable*, const QRectF& contentsRect, QskAspect::Subcontrol ) const
|
||||||
|
{
|
||||||
|
return contentsRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGNode* BlurredBoxSkinlet::updateSubNode(
|
||||||
|
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||||
|
{
|
||||||
|
const auto box = dynamic_cast< const BlurredBox* >( skinnable );
|
||||||
|
const auto r = box->subControlRect( BlurredBox::Panel );
|
||||||
|
|
||||||
|
if ( r.isEmpty() )
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto result = QskSkinlet::updateSubNode( skinnable, nodeRole, node );
|
||||||
|
|
||||||
|
switch ( nodeRole )
|
||||||
|
{
|
||||||
|
case PanelRole:
|
||||||
|
auto blurred = QskSGNode::ensureNode< BlurredBoxNode >( node );
|
||||||
|
auto rectOfScreen = box->rectOfScreen();
|
||||||
|
auto rectOnScreen = box->rectOnScreen();
|
||||||
|
blurred->setBlurData( r, box->shape(), rectOfScreen, rectOnScreen,
|
||||||
|
static_cast< float >( box->opacity() ), box->blurDirections(), box->blurQuality(),
|
||||||
|
box->blurSize() );
|
||||||
|
return blurred;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QskSGNode.h>
|
||||||
|
#include <QskSkinlet.h>
|
||||||
|
|
||||||
|
class BlurredBoxSkinlet : public QskSkinlet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum NodeRole
|
||||||
|
{
|
||||||
|
PanelRole
|
||||||
|
};
|
||||||
|
|
||||||
|
BlurredBoxSkinlet();
|
||||||
|
QRectF subControlRect(
|
||||||
|
const QskSkinnable*, const QRectF& contentsRect, QskAspect::Subcontrol ) const override;
|
||||||
|
QSGNode* updateSubNode(
|
||||||
|
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const override;
|
||||||
|
};
|
|
@ -0,0 +1,205 @@
|
||||||
|
#include "MainWindow.h"
|
||||||
|
#include "BlurredBox.h"
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QskLinearBox.h>
|
||||||
|
#include <QskStackBox.h>
|
||||||
|
|
||||||
|
#include <QskGraphic.h>
|
||||||
|
#include <QskGraphicLabel.h>
|
||||||
|
#include <QskSegmentedBar.h>
|
||||||
|
#include <QskShortcutMap.h>
|
||||||
|
#include <QskSkin.h>
|
||||||
|
#include <QskSlider.h>
|
||||||
|
#include <QskTextInput.h>
|
||||||
|
#include <QskTextLabel.h>
|
||||||
|
|
||||||
|
MainWindow::MainWindow()
|
||||||
|
{
|
||||||
|
constexpr QSize size = { 1280, 720 };
|
||||||
|
setMinimumSize( size );
|
||||||
|
setMaximumSize( size );
|
||||||
|
setTitle( tr( "Blurring" ) );
|
||||||
|
createBackground();
|
||||||
|
|
||||||
|
// create a centered, blurred and rounded rectangle
|
||||||
|
auto* const layout = new QskLinearBox( Qt::Vertical, contentItem() );
|
||||||
|
layout->setMargins( 40 );
|
||||||
|
auto* const stack = new QskStackBox( layout );
|
||||||
|
stack->setAutoLayoutChildren( true );
|
||||||
|
auto* const blurred = new BlurredBox( stack );
|
||||||
|
blurred->setShape( { 40, 40, 40, 40 } );
|
||||||
|
auto* const l = new QskLinearBox( Qt::Vertical, layout );
|
||||||
|
stack->addItem( l );
|
||||||
|
|
||||||
|
// create controls to change the rectangle
|
||||||
|
l->addSpacer( 10, 1 );
|
||||||
|
createBlurDirectionsControls( blurred, l );
|
||||||
|
createBlurQualityControls( blurred, l );
|
||||||
|
createBlurSizeControls( blurred, l );
|
||||||
|
createBlurOpacityControls( blurred, l );
|
||||||
|
createBlurCornerRadiiControls( blurred, l );
|
||||||
|
l->addSpacer( 10, 1 );
|
||||||
|
createShortcutNote( l );
|
||||||
|
l->addSpacer( 10, 1 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createBackground()
|
||||||
|
{
|
||||||
|
// create a brackground image
|
||||||
|
auto* const graphic = new QskGraphicLabel( contentItem() );
|
||||||
|
graphic->setFillMode( QskGraphicLabel::FillMode::Stretch );
|
||||||
|
graphic->setAlignment( Qt::AlignCenter );
|
||||||
|
|
||||||
|
// callback for rotating through the background images
|
||||||
|
auto updateBackground = [ this, graphic ]() {
|
||||||
|
static unsigned int index = 2;
|
||||||
|
index = 1 + ( index + 1 ) % 3;
|
||||||
|
const QImage image( QString( ":/backgrounds/background%1.jpg" ).arg( index ) );
|
||||||
|
graphic->setGraphic( QskGraphic::fromImage( image ) );
|
||||||
|
update();
|
||||||
|
};
|
||||||
|
updateBackground();
|
||||||
|
|
||||||
|
QKeySequence keys( Qt::CTRL | Qt::Key_Space );
|
||||||
|
QskShortcutMap::addShortcut( keys, false, contentItem(), updateBackground );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createBlurDirectionsControls( BlurredBox* blurred, QskLinearBox* layout )
|
||||||
|
{
|
||||||
|
auto* const label = new QskTextLabel( layout );
|
||||||
|
label->setTextColor( Qt::white );
|
||||||
|
label->setFontRole( QskSkin::MediumFont );
|
||||||
|
auto* const slider = new QskSlider( Qt::Horizontal, layout );
|
||||||
|
slider->setMinimum( 16.0 );
|
||||||
|
slider->setMaximum( 32.0 );
|
||||||
|
connect( slider, &QskSlider::valueChanged, [ blurred, label ]( qreal value ) {
|
||||||
|
blurred->setBlurDirections( static_cast< float >( value ) );
|
||||||
|
label->setText( QString( tr( "Blur Directions" ) + " ( %1 )" ).arg( value ) );
|
||||||
|
} );
|
||||||
|
slider->setValue( blurred->blurDirections() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createBlurQualityControls( BlurredBox* blurred, QskLinearBox* layout )
|
||||||
|
{
|
||||||
|
auto* const label = new QskTextLabel( layout );
|
||||||
|
label->setTextColor( Qt::white );
|
||||||
|
label->setFontRole( QskSkin::MediumFont );
|
||||||
|
auto* const slider = new QskSlider( Qt::Horizontal, layout );
|
||||||
|
slider->setMinimum( 4.0 );
|
||||||
|
slider->setMaximum( 16.0 );
|
||||||
|
connect( slider, &QskSlider::valueChanged, [ blurred, label ]( qreal value ) {
|
||||||
|
blurred->setBlurQuality( static_cast< float >( value ) );
|
||||||
|
label->setText( QString( tr( "Blur Quality" ) + " ( %1 )" ).arg( value ) );
|
||||||
|
} );
|
||||||
|
slider->setValue( blurred->blurQuality() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createBlurSizeControls( BlurredBox* blurred, QskLinearBox* layout )
|
||||||
|
{
|
||||||
|
auto* const label = new QskTextLabel( layout );
|
||||||
|
label->setTextColor( Qt::white );
|
||||||
|
label->setFontRole( QskSkin::MediumFont );
|
||||||
|
auto* const slider = new QskSlider( Qt::Horizontal, layout );
|
||||||
|
slider->setMinimum( 4.0 );
|
||||||
|
slider->setMaximum( 32.0 );
|
||||||
|
connect( slider, &QskSlider::valueChanged, [ blurred, label ]( qreal value ) {
|
||||||
|
blurred->setBlurSize( static_cast< float >( value ) );
|
||||||
|
label->setText( QString( tr( "Blur Size" ) + " ( %1 )" ).arg( value ) );
|
||||||
|
} );
|
||||||
|
slider->setValue( blurred->blurSize() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createBlurOpacityControls( BlurredBox* blurred, QskLinearBox* layout )
|
||||||
|
{
|
||||||
|
auto* const label = new QskTextLabel( layout );
|
||||||
|
label->setTextColor( Qt::white );
|
||||||
|
label->setFontRole( QskSkin::MediumFont );
|
||||||
|
auto* const slider = new QskSlider( Qt::Horizontal, layout );
|
||||||
|
slider->setMinimum( 0.0 );
|
||||||
|
slider->setMaximum( 1.0 );
|
||||||
|
connect( slider, &QskSlider::valueChanged, [ blurred, label ]( qreal value ) {
|
||||||
|
blurred->setOpacity( value );
|
||||||
|
label->setText( QString( tr( "Blur Opacity" ) + " ( %1 )" ).arg( value ) );
|
||||||
|
} );
|
||||||
|
slider->setValue( blurred->opacity() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createBlurCornerRadiiControls( BlurredBox* blurred, QskLinearBox* layout )
|
||||||
|
{
|
||||||
|
auto* const label = new QskTextLabel( layout );
|
||||||
|
label->setTextColor( Qt::white );
|
||||||
|
label->setFontRole( QskSkin::MediumFont );
|
||||||
|
auto* const bar = new QskSegmentedBar( Qt::Horizontal, layout );
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TL = 0,
|
||||||
|
TR = 1,
|
||||||
|
BR = 2,
|
||||||
|
BL = 3
|
||||||
|
};
|
||||||
|
bar->addText( "TL" );
|
||||||
|
bar->addText( "TR" );
|
||||||
|
bar->addText( "BR" );
|
||||||
|
bar->addText( "BL" );
|
||||||
|
auto* const slider = new QskSlider( Qt::Horizontal, layout );
|
||||||
|
slider->setMinimum( 0.0 );
|
||||||
|
slider->setMaximum( 80.0 );
|
||||||
|
connect( slider, &QskSlider::valueChanged, [ blurred, bar, label ]( qreal value ) {
|
||||||
|
auto shape = blurred->shape();
|
||||||
|
const auto format = tr( "Corner Radius" ) + " ( %1 )";
|
||||||
|
|
||||||
|
switch ( bar->currentIndex() )
|
||||||
|
{
|
||||||
|
case TL:
|
||||||
|
shape.setTopLeft( { value, value } );
|
||||||
|
break;
|
||||||
|
case TR:
|
||||||
|
shape.setTopRight( { value, value } );
|
||||||
|
break;
|
||||||
|
case BR:
|
||||||
|
shape.setBottomRight( { value, value } );
|
||||||
|
break;
|
||||||
|
case BL:
|
||||||
|
shape.setBottomLeft( { value, value } );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
label->setText( format.arg( value ) );
|
||||||
|
blurred->setShape( shape );
|
||||||
|
blurred->update();
|
||||||
|
} );
|
||||||
|
connect( bar, &QskSegmentedBar::currentIndexChanged, [ blurred, slider ]( int index ) {
|
||||||
|
const auto shape = blurred->shape();
|
||||||
|
|
||||||
|
switch ( index )
|
||||||
|
{
|
||||||
|
case TL:
|
||||||
|
slider->setValue( shape.topLeft().width() );
|
||||||
|
break;
|
||||||
|
case TR:
|
||||||
|
slider->setValue( shape.topRight().width() );
|
||||||
|
break;
|
||||||
|
case BR:
|
||||||
|
slider->setValue( shape.bottomRight().width() );
|
||||||
|
break;
|
||||||
|
case BL:
|
||||||
|
slider->setValue( shape.bottomLeft().width() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
slider->setValue( blurred->shape().topLeft().width() );
|
||||||
|
bar->setSelectedIndex( TL );
|
||||||
|
bar->setCurrentIndex( TL );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createShortcutNote( QskLinearBox* layout )
|
||||||
|
{
|
||||||
|
const auto text = tr( "Press 'Ctrl + Space' to change the background" );
|
||||||
|
auto* const label = new QskTextLabel( text, layout );
|
||||||
|
label->setTextColor( Qt::white );
|
||||||
|
label->setFontRole( QskSkin::LargeFont );
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_MainWindow.cpp"
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QskWindow.h>
|
||||||
|
|
||||||
|
class BlurredBox;
|
||||||
|
class QskLinearBox;
|
||||||
|
|
||||||
|
class MainWindow : public QskWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MainWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createBackground();
|
||||||
|
void createBlurDirectionsControls( BlurredBox* blurred, QskLinearBox* layout );
|
||||||
|
void createBlurQualityControls( BlurredBox* blurred, QskLinearBox* layout );
|
||||||
|
void createBlurSizeControls( BlurredBox* blurred, QskLinearBox* layout );
|
||||||
|
void createBlurOpacityControls( BlurredBox* blurred, QskLinearBox* layout );
|
||||||
|
void createBlurCornerRadiiControls( BlurredBox* blurred, QskLinearBox* layout );
|
||||||
|
void createShortcutNote( QskLinearBox* layout );
|
||||||
|
};
|
Binary file not shown.
After Width: | Height: | Size: 616 KiB |
Binary file not shown.
After Width: | Height: | Size: 112 KiB |
Binary file not shown.
After Width: | Height: | Size: 236 KiB |
|
@ -0,0 +1,23 @@
|
||||||
|
CONFIG += qskexample
|
||||||
|
|
||||||
|
QT += quick_private # TODO: examples should not use private headers
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
main.cpp \
|
||||||
|
MainWindow.cpp \
|
||||||
|
BlurredBox.cpp \
|
||||||
|
BlurredBoxMaterial.cpp \
|
||||||
|
BlurredBoxMaterialShader.cpp \
|
||||||
|
BlurredBoxNode.cpp \
|
||||||
|
BlurredBoxSkinlet.cpp \
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
MainWindow.h \
|
||||||
|
BlurredBox.h \
|
||||||
|
BlurredBoxMaterial.h \
|
||||||
|
BlurredBoxMaterialShader.h \
|
||||||
|
BlurredBoxNode.h \
|
||||||
|
BlurredBoxSkinlet.h \
|
||||||
|
|
||||||
|
RESOURCES += \
|
||||||
|
blurringshaders.qrc
|
|
@ -0,0 +1,9 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>shaders/blurredbox.vert</file>
|
||||||
|
<file>shaders/blurredbox.frag</file>
|
||||||
|
<file>backgrounds/background1.jpg</file>
|
||||||
|
<file>backgrounds/background2.jpg</file>
|
||||||
|
<file>backgrounds/background3.jpg</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
|
@ -0,0 +1,35 @@
|
||||||
|
#include <SkinnyShortcut.h>
|
||||||
|
|
||||||
|
#include <QskObjectCounter.h>
|
||||||
|
#include <QskSetup.h>
|
||||||
|
#include <QskShortcutMap.h>
|
||||||
|
#include <QskSkinFactory.h>
|
||||||
|
#include <QskSkinManager.h>
|
||||||
|
#include <QskWindow.h>
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
|
||||||
|
#include "MainWindow.h"
|
||||||
|
|
||||||
|
int main( int argc, char* argv[] )
|
||||||
|
{
|
||||||
|
#ifdef ITEM_STATISTICS
|
||||||
|
QskObjectCounter counter( true );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QGuiApplication app( argc, argv );
|
||||||
|
|
||||||
|
qskSetup->setItemUpdateFlag( QskQuickItem::PreferRasterForTextures, true );
|
||||||
|
|
||||||
|
// disable default skins
|
||||||
|
qskSkinManager->setPluginPaths( QStringList() ); // no plugins
|
||||||
|
|
||||||
|
// With CTRL-B you can rotate a couple of visual debug modes
|
||||||
|
SkinnyShortcut::enable( SkinnyShortcut::RotateSkin | SkinnyShortcut::DebugBackground |
|
||||||
|
SkinnyShortcut::DebugStatistics | SkinnyShortcut::Quit );
|
||||||
|
|
||||||
|
MainWindow window;
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
// opacity of the rectangle
|
||||||
|
uniform lowp float rectOpacity;
|
||||||
|
// x = top left, y = top right, z = bottom right, w = bottom left
|
||||||
|
uniform lowp vec4 rectCornerRadii;
|
||||||
|
// the rectangle on the screen (x, y, width, height)
|
||||||
|
uniform lowp vec4 rectOnScreen;
|
||||||
|
// the screen's rectangle (x, y, width, height)
|
||||||
|
uniform lowp vec4 rectOfScreen;
|
||||||
|
// must be greater than 0.0!
|
||||||
|
uniform lowp float blurDirections;
|
||||||
|
// must be greater than 0.0!
|
||||||
|
uniform lowp float blurQuality;
|
||||||
|
// the radius for blurring
|
||||||
|
uniform lowp float blurSize;
|
||||||
|
|
||||||
|
// normalized position of the fragment
|
||||||
|
varying lowp vec2 coord;
|
||||||
|
|
||||||
|
// the texture
|
||||||
|
uniform sampler2D txr;
|
||||||
|
|
||||||
|
lowp float effectiveRadius( in lowp vec4 radii, in lowp vec2 point )
|
||||||
|
{
|
||||||
|
// aliases
|
||||||
|
lowp float px = point.x * rectOfScreen.z;
|
||||||
|
lowp float py = point.y * rectOfScreen.w;
|
||||||
|
lowp float rx = rectOnScreen.x;
|
||||||
|
lowp float ry = rectOnScreen.y;
|
||||||
|
lowp float rw = rectOnScreen.z;
|
||||||
|
lowp float rh = rectOnScreen.w;
|
||||||
|
|
||||||
|
// predicates
|
||||||
|
bool l = px >= rx && px < rx + rw / 2.0;
|
||||||
|
bool r = px >= rx + rw / 2.0 && px < rx + rw;
|
||||||
|
bool t = py >= ry && py < ry + rh / 2.0;
|
||||||
|
bool b = py >= ry + rh / 2.0 && py < ry + rh;
|
||||||
|
|
||||||
|
if ( t && l) return radii.x;
|
||||||
|
if ( t && r) return radii.y;
|
||||||
|
if ( b && r) return radii.z;
|
||||||
|
if ( b && l) return radii.w;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// from https://iquilezles.org/articles/distfunctions
|
||||||
|
lowp float roundedBoxSDF(vec2 centerPosition, vec2 size, lowp float radius)
|
||||||
|
{
|
||||||
|
return length( max( abs(centerPosition) - size + radius, 0.0) ) - radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
// source: https://www.shadertoy.com/view/Xltfzj
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
if(rectOpacity == 0.0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Radius for blurring around the pixel
|
||||||
|
vec2 blurRadius = blurSize / rectOnScreen.zw;
|
||||||
|
|
||||||
|
// Pixel colour
|
||||||
|
vec4 fragColor = texture2D(txr, coord);
|
||||||
|
|
||||||
|
// Blur calculations
|
||||||
|
const lowp float Pi = 6.28318530718; // constant for Pi*2
|
||||||
|
for( float d = 0.0; d < Pi; d += Pi / blurDirections)
|
||||||
|
{
|
||||||
|
for(float i = 1.0 / blurQuality; i <= 1.0; i += 1.0 / blurQuality)
|
||||||
|
{
|
||||||
|
fragColor += texture2D( txr, coord + vec2(cos(d), sin(d)) * blurRadius * i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lowp float cornerRadius = effectiveRadius(rectCornerRadii, coord);
|
||||||
|
lowp float edgeSoftness = 1.0f;
|
||||||
|
lowp float distance = roundedBoxSDF(coord * rectOfScreen.zw - rectOnScreen.xy - rectOnScreen.zw * 0.5f, rectOnScreen.zw * 0.5f, cornerRadius);
|
||||||
|
lowp float smoothedAlpha = 1.0f - smoothstep(0.0f, edgeSoftness * 2.0f, distance);
|
||||||
|
|
||||||
|
// Output to screen
|
||||||
|
fragColor /= blurQuality * blurDirections - 15.0;
|
||||||
|
|
||||||
|
gl_FragColor = mix(texture2D( txr, coord), fragColor, smoothedAlpha) * rectOpacity;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
uniform highp mat4 matrix;
|
||||||
|
|
||||||
|
attribute highp vec4 in_vertex;
|
||||||
|
attribute mediump vec2 in_coord;
|
||||||
|
|
||||||
|
varying mediump vec2 coord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
coord = in_coord;
|
||||||
|
gl_Position = matrix * in_vertex;
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ TEMPLATE = subdirs
|
||||||
|
|
||||||
# c++
|
# c++
|
||||||
SUBDIRS += \
|
SUBDIRS += \
|
||||||
|
blurredbox \
|
||||||
desktop \
|
desktop \
|
||||||
gallery \
|
gallery \
|
||||||
layouts \
|
layouts \
|
||||||
|
|
Loading…
Reference in New Issue