Merge branch 'master' of https://github.com/uwerat/qskinny
This commit is contained in:
commit
411e9832fd
@ -8,14 +8,9 @@
|
|||||||
|
|
||||||
#include <QskTextLabel.h>
|
#include <QskTextLabel.h>
|
||||||
|
|
||||||
QSK_SUBCONTROL( Box, Panel )
|
|
||||||
|
|
||||||
Box::Box( const QString& title, QQuickItem* parent )
|
Box::Box( const QString& title, QQuickItem* parent )
|
||||||
: QskLinearBox( Qt::Vertical, parent )
|
: ShadowedBox( Qt::Vertical, parent )
|
||||||
{
|
{
|
||||||
setPanel( true );
|
|
||||||
setSubcontrolProxy( QskBox::Panel, Box::Panel );
|
|
||||||
|
|
||||||
if ( !title.isEmpty() )
|
if ( !title.isEmpty() )
|
||||||
{
|
{
|
||||||
auto label = new QskTextLabel( title, this );
|
auto label = new QskTextLabel( title, this );
|
||||||
|
@ -5,16 +5,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QskLinearBox.h>
|
#include "ShadowedBox.h"
|
||||||
|
|
||||||
class QskTextLabel;
|
class Box : public ShadowedBox
|
||||||
|
|
||||||
class Box : public QskLinearBox
|
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QSK_SUBCONTROLS( Panel )
|
|
||||||
|
|
||||||
Box( const QString& title, QQuickItem* parent = nullptr );
|
Box( const QString& title, QQuickItem* parent = nullptr );
|
||||||
};
|
};
|
||||||
|
@ -36,7 +36,6 @@ BoxWithButtons::BoxWithButtons( const QString& title, const QString& value,
|
|||||||
bool isBright, QQuickItem* parent )
|
bool isBright, QQuickItem* parent )
|
||||||
: Box( QString(), parent )
|
: Box( QString(), parent )
|
||||||
{
|
{
|
||||||
setPanel( true );
|
|
||||||
setSubcontrolProxy( QskBox::Panel, Panel );
|
setSubcontrolProxy( QskBox::Panel, Panel );
|
||||||
|
|
||||||
setSizePolicy( Qt::Vertical, QskSizePolicy::Maximum );
|
setSizePolicy( Qt::Vertical, QskSizePolicy::Maximum );
|
||||||
|
@ -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"
|
||||||
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
179
examples/iotdashboard/ShadowedBox.cpp
Normal file
179
examples/iotdashboard/ShadowedBox.cpp
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the 3-clause BSD License
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "ShadowedBox.h"
|
||||||
|
#include "nodes/BoxShadowNode.h"
|
||||||
|
|
||||||
|
#include <QskBoxNode.h>
|
||||||
|
#include <QskBoxBorderMetrics.h>
|
||||||
|
#include <QskBoxBorderColors.h>
|
||||||
|
#include <QskGradient.h>
|
||||||
|
#include <QskSkinlet.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class Skinlet : public QskSkinlet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum NodeRole { ShadowRole, PanelRole };
|
||||||
|
|
||||||
|
Skinlet()
|
||||||
|
{
|
||||||
|
setNodeRoles( { ShadowRole, PanelRole } );
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF subControlRect( const QskSkinnable*,
|
||||||
|
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const override
|
||||||
|
{
|
||||||
|
if ( subControl == ShadowedBox::Panel )
|
||||||
|
{
|
||||||
|
return contentsRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QRectF();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGNode* updateSubNode( const QskSkinnable* skinnable,
|
||||||
|
quint8 nodeRole, QSGNode* node ) const override
|
||||||
|
{
|
||||||
|
const auto box = static_cast< const ShadowedBox* >( skinnable );
|
||||||
|
|
||||||
|
const auto r = box->subControlRect( ShadowedBox::Panel );
|
||||||
|
if ( r.isEmpty() )
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
switch ( nodeRole )
|
||||||
|
{
|
||||||
|
case ShadowRole:
|
||||||
|
{
|
||||||
|
auto shadowNode = static_cast< BoxShadowNode* >( node );
|
||||||
|
if ( shadowNode == nullptr )
|
||||||
|
shadowNode = new BoxShadowNode();
|
||||||
|
|
||||||
|
const auto& shadowMetrics = box->shadow();
|
||||||
|
|
||||||
|
shadowNode->setRect( shadowMetrics.shadowRect( r ) );
|
||||||
|
shadowNode->setShape( box->shape() );
|
||||||
|
shadowNode->setBlurRadius( shadowMetrics.blurRadius() );
|
||||||
|
shadowNode->setColor( box->shadowColor() );
|
||||||
|
shadowNode->setClipRect( r );
|
||||||
|
|
||||||
|
shadowNode->updateGeometry();
|
||||||
|
|
||||||
|
return shadowNode;
|
||||||
|
}
|
||||||
|
case PanelRole:
|
||||||
|
{
|
||||||
|
auto boxNode = static_cast< QskBoxNode* >( node );
|
||||||
|
if ( boxNode == nullptr )
|
||||||
|
boxNode = new QskBoxNode();
|
||||||
|
|
||||||
|
const auto r = box->subControlRect( ShadowedBox::Panel );
|
||||||
|
|
||||||
|
boxNode->setBoxData( r, box->shape(), box->borderWidth(),
|
||||||
|
box->borderColor(), box->gradient() );
|
||||||
|
|
||||||
|
return boxNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
QSK_SUBCONTROL( ShadowedBox, Panel )
|
||||||
|
|
||||||
|
ShadowedBox::ShadowedBox(Qt::Orientation orientation, QQuickItem* parentItem )
|
||||||
|
: QskLinearBox( orientation, parentItem )
|
||||||
|
{
|
||||||
|
setFlag( QQuickItem::ItemHasContents, true );
|
||||||
|
setSkinlet( new Skinlet() );
|
||||||
|
|
||||||
|
// ### move to Skin:
|
||||||
|
setGradient( Qt::white );
|
||||||
|
setShadow( { 0, 10 } );
|
||||||
|
setShadowColor( 0xe5e5e5 );
|
||||||
|
setShape( 6 );
|
||||||
|
}
|
||||||
|
|
||||||
|
ShadowedBox::~ShadowedBox()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowedBox::setShadow( const QskShadowMetrics& shadow )
|
||||||
|
{
|
||||||
|
m_shadow = shadow;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QskShadowMetrics& ShadowedBox::shadow() const
|
||||||
|
{
|
||||||
|
return m_shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowedBox::setShadowColor( const QColor& color )
|
||||||
|
{
|
||||||
|
m_shadowColor = color;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor ShadowedBox::shadowColor() const
|
||||||
|
{
|
||||||
|
return m_shadowColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF ShadowedBox::layoutRectForSize( const QSizeF &size ) const
|
||||||
|
{
|
||||||
|
auto padding = paddingHint( Panel );
|
||||||
|
return { padding.left() / 2, padding.top() / 2,
|
||||||
|
size.width() - padding.right(), size.height() - padding.bottom() };
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowedBox::setGradient( const QskGradient& gradient )
|
||||||
|
{
|
||||||
|
m_gradient = gradient;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QskGradient& ShadowedBox::gradient() const
|
||||||
|
{
|
||||||
|
return m_gradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowedBox::setShape( const QskBoxShapeMetrics& shape )
|
||||||
|
{
|
||||||
|
m_shape = shape;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QskBoxShapeMetrics& ShadowedBox::shape() const
|
||||||
|
{
|
||||||
|
return m_shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowedBox::setBorderWidth( qreal width )
|
||||||
|
{
|
||||||
|
m_borderWidth = qMax( width, 0.0 );
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal ShadowedBox::borderWidth() const
|
||||||
|
{
|
||||||
|
return m_borderWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowedBox::setBorderColor( const QColor& color )
|
||||||
|
{
|
||||||
|
m_borderColor = color;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor ShadowedBox::borderColor() const
|
||||||
|
{
|
||||||
|
return m_borderColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_ShadowedBox.cpp"
|
53
examples/iotdashboard/ShadowedBox.h
Normal file
53
examples/iotdashboard/ShadowedBox.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the 3-clause BSD License
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QskLinearBox.h>
|
||||||
|
#include <QskBoxShapeMetrics.h>
|
||||||
|
#include <QskShadowMetrics.h>
|
||||||
|
|
||||||
|
class QskGradient;
|
||||||
|
|
||||||
|
class ShadowedBox : public QskLinearBox
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QSK_SUBCONTROLS( Panel )
|
||||||
|
|
||||||
|
ShadowedBox( Qt::Orientation orientation, QQuickItem* parent = nullptr );
|
||||||
|
~ShadowedBox() override;
|
||||||
|
|
||||||
|
void setShadow( const QskShadowMetrics& );
|
||||||
|
const QskShadowMetrics& shadow() const;
|
||||||
|
|
||||||
|
void setGradient( const QskGradient& );
|
||||||
|
const QskGradient& gradient() const;
|
||||||
|
|
||||||
|
void setShadowColor( const QColor& );
|
||||||
|
QColor shadowColor() const;
|
||||||
|
|
||||||
|
QRectF layoutRectForSize( const QSizeF& size ) const override;
|
||||||
|
|
||||||
|
void setShape( const QskBoxShapeMetrics& );
|
||||||
|
const QskBoxShapeMetrics& shape() const;
|
||||||
|
|
||||||
|
void setBorderWidth( qreal width );
|
||||||
|
qreal borderWidth() const;
|
||||||
|
|
||||||
|
void setBorderColor( const QColor& );
|
||||||
|
QColor borderColor() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QskShadowMetrics m_shadow;
|
||||||
|
QColor m_shadowColor = Qt::black;
|
||||||
|
|
||||||
|
QskGradient m_gradient;
|
||||||
|
QskBoxShapeMetrics m_shape;
|
||||||
|
|
||||||
|
qreal m_borderWidth = 0.0;
|
||||||
|
QColor m_borderColor = Qt::black;
|
||||||
|
};
|
@ -16,8 +16,9 @@
|
|||||||
#include "MenuBar.h"
|
#include "MenuBar.h"
|
||||||
#include "PieChartPainted.h"
|
#include "PieChartPainted.h"
|
||||||
#include "RoundedIcon.h"
|
#include "RoundedIcon.h"
|
||||||
#include "TopBar.h"
|
|
||||||
#include "RoundButton.h"
|
#include "RoundButton.h"
|
||||||
|
#include "ShadowedBox.h"
|
||||||
|
#include "TopBar.h"
|
||||||
#include "UsageBox.h"
|
#include "UsageBox.h"
|
||||||
#include "UsageDiagram.h"
|
#include "UsageDiagram.h"
|
||||||
|
|
||||||
@ -125,13 +126,8 @@ void Skin::initHints( const Palette& palette )
|
|||||||
ed.setFontRole( TimeLabel::Text, QskSkin::HugeFont );
|
ed.setFontRole( TimeLabel::Text, QskSkin::HugeFont );
|
||||||
ed.setColor( TimeLabel::Text, "#6776FF" );
|
ed.setColor( TimeLabel::Text, "#6776FF" );
|
||||||
|
|
||||||
|
|
||||||
// boxes (including shadow):
|
// boxes (including shadow):
|
||||||
ed.setPadding( Box::Panel, 15 );
|
ed.setPadding( ShadowedBox::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 +196,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 );
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ class DaytimeSkin : public Skin
|
|||||||
: Skin(
|
: Skin(
|
||||||
Skin::Palette( {"#6D7BFB"}, {"#fbfbfb"}, {"#ffffff"},
|
Skin::Palette( {"#6D7BFB"}, {"#fbfbfb"}, {"#ffffff"},
|
||||||
"#ffffff", {"#f7f7f7"}, {"#f4f4f4"}, Qt::black, Qt::black,
|
"#ffffff", {"#f7f7f7"}, {"#f4f4f4"}, Qt::black, Qt::black,
|
||||||
{ QskGradient::Vertical, { { 0.0, 0xc4c4c4 }, { 0.5, 0xf8f8f8 }, { 1.0, 0xc4c4c4 } } } )
|
{ QskGradient::Vertical, { { 0.0, 0xffc4c4c4 }, { 0.5, 0xfff8f8f8 }, { 1.0, 0xffc4c4c4 } } } )
|
||||||
, parent )
|
, parent )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ class NighttimeSkin : public Skin
|
|||||||
: Skin(
|
: Skin(
|
||||||
Skin::Palette( {"#2937A7"}, {"#040404"}, {"#000000"},
|
Skin::Palette( {"#2937A7"}, {"#040404"}, {"#000000"},
|
||||||
"#000000", {"#0a0a0a"}, {"#0c0c0c"}, Qt::white, Qt::white,
|
"#000000", {"#0a0a0a"}, {"#0c0c0c"}, Qt::white, Qt::white,
|
||||||
{ QskGradient::Vertical, { { 0.0, 0x666666 }, { 0.5, 0x222222 }, { 1.0, 0x333333 } } } )
|
{ QskGradient::Vertical, { { 0.0, 0xff666666 }, { 0.5, 0xff222222 }, { 1.0, 0xff333333 } } } )
|
||||||
, parent )
|
, parent )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ SOURCES += \
|
|||||||
PieChartPainted.cpp \
|
PieChartPainted.cpp \
|
||||||
PieChartSkinlet.cpp \
|
PieChartSkinlet.cpp \
|
||||||
RoundedIcon.cpp \
|
RoundedIcon.cpp \
|
||||||
|
ShadowedBox.cpp \
|
||||||
Skin.cpp \
|
Skin.cpp \
|
||||||
TopBar.cpp \
|
TopBar.cpp \
|
||||||
RoundButton.cpp \
|
RoundButton.cpp \
|
||||||
@ -28,7 +29,8 @@ SOURCES += \
|
|||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
nodes/DiagramDataNode.cpp \
|
nodes/DiagramDataNode.cpp \
|
||||||
nodes/DiagramSegmentsNode.cpp
|
nodes/DiagramSegmentsNode.cpp \
|
||||||
|
nodes/BoxShadowNode.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
Box.h \
|
Box.h \
|
||||||
@ -47,6 +49,7 @@ HEADERS += \
|
|||||||
PieChartPainted.h \
|
PieChartPainted.h \
|
||||||
PieChartSkinlet.h \
|
PieChartSkinlet.h \
|
||||||
RoundedIcon.h \
|
RoundedIcon.h \
|
||||||
|
ShadowedBox.h \
|
||||||
Skin.h \
|
Skin.h \
|
||||||
TopBar.h \
|
TopBar.h \
|
||||||
RoundButton.h \
|
RoundButton.h \
|
||||||
@ -55,23 +58,10 @@ HEADERS += \
|
|||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
nodes/DiagramDataNode.h \
|
nodes/DiagramDataNode.h \
|
||||||
nodes/DiagramSegmentsNode.h
|
nodes/DiagramSegmentsNode.h \
|
||||||
|
nodes/BoxShadowNode.h
|
||||||
HEADERS += \
|
|
||||||
kirigami/shadowedrectangle.h \
|
|
||||||
kirigami/scenegraph/paintedrectangleitem.h \
|
|
||||||
kirigami/scenegraph/shadowedborderrectanglematerial.h \
|
|
||||||
kirigami/scenegraph/shadowedrectanglematerial.h \
|
|
||||||
kirigami/scenegraph/shadowedrectanglenode.h
|
|
||||||
|
|
||||||
SOURCES += \
|
|
||||||
kirigami/shadowedrectangle.cpp \
|
|
||||||
kirigami/scenegraph/paintedrectangleitem.cpp \
|
|
||||||
kirigami/scenegraph/shadowedborderrectanglematerial.cpp \
|
|
||||||
kirigami/scenegraph/shadowedrectanglematerial.cpp \
|
|
||||||
kirigami/scenegraph/shadowedrectanglenode.cpp
|
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
images.qrc \
|
images.qrc \
|
||||||
fonts.qrc \
|
fonts.qrc \
|
||||||
kirigami/scenegraph/shaders/shaders.qrc
|
shaders.qrc
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
@ -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>
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
|
||||||
};
|
|
@ -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
|
|
||||||
});
|
|
||||||
}
|
|
@ -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;
|
|
||||||
};
|
|
@ -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;
|
|
||||||
}
|
|
@ -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;
|
|
||||||
};
|
|
@ -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 );
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
|
||||||
};
|
|
257
examples/iotdashboard/nodes/BoxShadowNode.cpp
Normal file
257
examples/iotdashboard/nodes/BoxShadowNode.cpp
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the 3-clause BSD License
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "BoxShadowNode.h"
|
||||||
|
#include "QskBoxShapeMetrics.h"
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QSGMaterialShader>
|
||||||
|
#include <QSGMaterial>
|
||||||
|
|
||||||
|
#include <private/qsgnode_p.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class Shader final : public QSGMaterialShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Shader();
|
||||||
|
|
||||||
|
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_opacityId = -1;
|
||||||
|
int m_aspectId = -1;
|
||||||
|
int m_blurExtentId = -1;
|
||||||
|
int m_radiusId = -1;
|
||||||
|
int m_colorId = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Material final : public QSGMaterial
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Material();
|
||||||
|
|
||||||
|
QSGMaterialShader* createShader() const override;
|
||||||
|
|
||||||
|
QSGMaterialType* type() const override;
|
||||||
|
|
||||||
|
int compare( const QSGMaterial* other ) const override;
|
||||||
|
|
||||||
|
QVector2D aspect = QVector2D{1.0, 1.0};
|
||||||
|
float blurExtent = 0.0;
|
||||||
|
QVector4D radius = QVector4D{0.0, 0.0, 0.0, 0.0};
|
||||||
|
QColor color = Qt::black;
|
||||||
|
};
|
||||||
|
|
||||||
|
Shader::Shader()
|
||||||
|
{
|
||||||
|
const QString root( ":/iotdashboard/shaders/" );
|
||||||
|
|
||||||
|
setShaderSourceFile( QOpenGLShader::Vertex, root + "boxshadow.vert" );
|
||||||
|
setShaderSourceFile( QOpenGLShader::Fragment, root + "boxshadow.frag" );
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* const* Shader::attributeNames() const
|
||||||
|
{
|
||||||
|
static char const* const names[] = { "in_vertex", "in_coord", nullptr };
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::initialize()
|
||||||
|
{
|
||||||
|
QSGMaterialShader::initialize();
|
||||||
|
|
||||||
|
auto p = program();
|
||||||
|
|
||||||
|
m_matrixId = p->uniformLocation( "matrix" );
|
||||||
|
m_aspectId = p->uniformLocation( "aspect" );
|
||||||
|
m_opacityId = p->uniformLocation( "opacity" );
|
||||||
|
m_blurExtentId = p->uniformLocation( "blurExtent" );
|
||||||
|
m_radiusId = p->uniformLocation( "radius" );
|
||||||
|
m_colorId = p->uniformLocation( "color" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::updateState( const QSGMaterialShader::RenderState& state,
|
||||||
|
QSGMaterial* newMaterial, QSGMaterial* oldMaterial )
|
||||||
|
{
|
||||||
|
auto p = program();
|
||||||
|
|
||||||
|
if ( state.isMatrixDirty() )
|
||||||
|
p->setUniformValue( m_matrixId, state.combinedMatrix() );
|
||||||
|
|
||||||
|
if ( state.isOpacityDirty() )
|
||||||
|
p->setUniformValue( m_opacityId, state.opacity() );
|
||||||
|
|
||||||
|
if ( oldMaterial == nullptr || newMaterial->compare( oldMaterial ) != 0
|
||||||
|
|| state.isCachedMaterialDataDirty( ))
|
||||||
|
{
|
||||||
|
auto material = static_cast< const Material* >( newMaterial );
|
||||||
|
|
||||||
|
p->setUniformValue( m_aspectId, material->aspect );
|
||||||
|
p->setUniformValue( m_blurExtentId, material->blurExtent);
|
||||||
|
p->setUniformValue( m_radiusId, material->radius );
|
||||||
|
p->setUniformValue( m_colorId, material->color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Material::Material()
|
||||||
|
{
|
||||||
|
setFlag( QSGMaterial::Blending, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGMaterialShader* Material::createShader() const
|
||||||
|
{
|
||||||
|
return new Shader();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGMaterialType* Material::type() const
|
||||||
|
{
|
||||||
|
static QSGMaterialType staticType;
|
||||||
|
return &staticType;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Material::compare( const QSGMaterial* other ) const
|
||||||
|
{
|
||||||
|
auto material = static_cast< const Material* >( other );
|
||||||
|
|
||||||
|
if ( material->color == color
|
||||||
|
&& material->aspect == aspect
|
||||||
|
&& qFuzzyCompare(material->blurExtent, blurExtent)
|
||||||
|
&& qFuzzyCompare(material->radius, radius) )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QSGMaterial::compare(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BoxShadowNodePrivate final : public QSGGeometryNodePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BoxShadowNodePrivate()
|
||||||
|
: geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGGeometry geometry;
|
||||||
|
Material material;
|
||||||
|
|
||||||
|
QRectF rect;
|
||||||
|
};
|
||||||
|
|
||||||
|
BoxShadowNode::BoxShadowNode()
|
||||||
|
: QSGGeometryNode( *new BoxShadowNodePrivate )
|
||||||
|
{
|
||||||
|
Q_D( BoxShadowNode );
|
||||||
|
|
||||||
|
setGeometry( &d->geometry );
|
||||||
|
setMaterial( &d->material );
|
||||||
|
}
|
||||||
|
|
||||||
|
BoxShadowNode::~BoxShadowNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShadowNode::setRect( const QRectF& rect )
|
||||||
|
{
|
||||||
|
Q_D( BoxShadowNode );
|
||||||
|
|
||||||
|
if ( rect == d->rect )
|
||||||
|
return;
|
||||||
|
|
||||||
|
d->rect = rect;
|
||||||
|
|
||||||
|
QVector2D aspect( 1.0, 1.0 );
|
||||||
|
|
||||||
|
if ( rect.width() >= rect.height() )
|
||||||
|
aspect.setX( rect.width() / rect.height() );
|
||||||
|
else
|
||||||
|
aspect.setY( rect.height() / rect.width() );
|
||||||
|
|
||||||
|
if ( d->material.aspect != aspect )
|
||||||
|
{
|
||||||
|
d->material.aspect = aspect;
|
||||||
|
markDirty( QSGNode::DirtyMaterial );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShadowNode::setShape( const QskBoxShapeMetrics& shape )
|
||||||
|
{
|
||||||
|
Q_D( BoxShadowNode );
|
||||||
|
|
||||||
|
const float t = std::min( d->rect.width(), d->rect.height() );
|
||||||
|
|
||||||
|
const float r1 = shape.radius( Qt::BottomRightCorner ).width();
|
||||||
|
const float r2 = shape.radius( Qt::TopRightCorner ).width();
|
||||||
|
const float r3 = shape.radius( Qt::BottomLeftCorner ).width();
|
||||||
|
const float r4 = shape.radius( Qt::TopLeftCorner ).width();
|
||||||
|
|
||||||
|
const auto uniformRadius = QVector4D(
|
||||||
|
std::min( r1 / t, 1.0f ), std::min( r2 / t, 1.0f ),
|
||||||
|
std::min( r3 / t, 1.0f ), std::min( r4 / t, 1.0f ) );
|
||||||
|
|
||||||
|
if ( d->material.radius != uniformRadius )
|
||||||
|
{
|
||||||
|
d->material.radius = uniformRadius;
|
||||||
|
|
||||||
|
markDirty( QSGNode::DirtyMaterial );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShadowNode::setColor( const QColor& color )
|
||||||
|
{
|
||||||
|
Q_D( BoxShadowNode );
|
||||||
|
|
||||||
|
const auto a = color.alphaF();
|
||||||
|
|
||||||
|
const auto c = QColor::fromRgbF(
|
||||||
|
color.redF() * a, color.greenF() * a, color.blueF() * a, a );
|
||||||
|
|
||||||
|
if ( d->material.color != c )
|
||||||
|
{
|
||||||
|
d->material.color = c;
|
||||||
|
markDirty( QSGNode::DirtyMaterial );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShadowNode::setBlurRadius( qreal blurRadius )
|
||||||
|
{
|
||||||
|
Q_D( BoxShadowNode );
|
||||||
|
|
||||||
|
if ( blurRadius <= 0.0 )
|
||||||
|
blurRadius = 0.0;
|
||||||
|
|
||||||
|
const float t = 0.5 * std::min( d->rect.width(), d->rect.height() );
|
||||||
|
const float uniformExtent = blurRadius / t;
|
||||||
|
|
||||||
|
if ( !qFuzzyCompare( d->material.blurExtent, uniformExtent ) )
|
||||||
|
{
|
||||||
|
d->material.blurExtent = uniformExtent;
|
||||||
|
markDirty( QSGNode::DirtyMaterial );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShadowNode::setClipRect( const QRectF& rect )
|
||||||
|
{
|
||||||
|
Q_UNUSED( rect )
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShadowNode::updateGeometry()
|
||||||
|
{
|
||||||
|
Q_D( BoxShadowNode );
|
||||||
|
|
||||||
|
QSGGeometry::updateTexturedRectGeometry(
|
||||||
|
&d->geometry, d->rect, QRectF( -0.5, -0.5, 1.0, 1.0 ) );
|
||||||
|
|
||||||
|
markDirty( QSGNode::DirtyGeometry );
|
||||||
|
}
|
32
examples/iotdashboard/nodes/BoxShadowNode.h
Normal file
32
examples/iotdashboard/nodes/BoxShadowNode.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the 3-clause BSD License
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QSGGeometryNode>
|
||||||
|
|
||||||
|
class QColor;
|
||||||
|
class QskBoxShapeMetrics;
|
||||||
|
|
||||||
|
class BoxShadowNodePrivate;
|
||||||
|
|
||||||
|
class BoxShadowNode : public QSGGeometryNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BoxShadowNode();
|
||||||
|
~BoxShadowNode() override;
|
||||||
|
|
||||||
|
void setRect( const QRectF& );
|
||||||
|
void setShape( const QskBoxShapeMetrics& );
|
||||||
|
void setColor( const QColor& );
|
||||||
|
void setBlurRadius( qreal );
|
||||||
|
|
||||||
|
void setClipRect( const QRectF& );
|
||||||
|
|
||||||
|
void updateGeometry();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DECLARE_PRIVATE( BoxShadowNode )
|
||||||
|
};
|
7
examples/iotdashboard/shaders.qrc
Normal file
7
examples/iotdashboard/shaders.qrc
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE RCC>
|
||||||
|
<RCC version="1.0">
|
||||||
|
<qresource prefix="/iotdashboard">
|
||||||
|
<file>shaders/boxshadow.vert</file>
|
||||||
|
<file>shaders/boxshadow.frag</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
42
examples/iotdashboard/shaders/boxshadow.frag
Normal file
42
examples/iotdashboard/shaders/boxshadow.frag
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
uniform lowp float opacity;
|
||||||
|
uniform lowp float blurExtent;
|
||||||
|
uniform lowp vec4 radius;
|
||||||
|
uniform lowp vec4 color;
|
||||||
|
uniform lowp vec2 aspect;
|
||||||
|
|
||||||
|
varying lowp vec2 coord;
|
||||||
|
|
||||||
|
lowp float effectiveRadius( in lowp vec4 radii, in lowp vec2 point )
|
||||||
|
{
|
||||||
|
if ( point.x > 0.0 )
|
||||||
|
return ( point.y > 0.0) ? radii.x : radii.y;
|
||||||
|
else
|
||||||
|
return ( point.y > 0.0) ? radii.z : radii.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
lowp vec4 col = vec4(0.0);
|
||||||
|
|
||||||
|
if ( opacity > 0.0 )
|
||||||
|
{
|
||||||
|
const lowp float minRadius = 0.05;
|
||||||
|
|
||||||
|
lowp float e2 = 0.5 * blurExtent;
|
||||||
|
lowp float r = 2.0 * effectiveRadius( radius, coord );
|
||||||
|
|
||||||
|
lowp float f = minRadius / max( r, minRadius );
|
||||||
|
|
||||||
|
r += e2 * f;
|
||||||
|
|
||||||
|
lowp vec2 d = r + blurExtent - aspect * ( 1.0 - abs( 2.0 * coord ) );
|
||||||
|
lowp float l = min( max(d.x, d.y), 0.0) + length( max(d, 0.0) );
|
||||||
|
|
||||||
|
lowp float shadow = l - r;
|
||||||
|
|
||||||
|
lowp float v = smoothstep( -e2, e2, shadow );
|
||||||
|
col = mix( color, vec4(0.0), v ) * opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FragColor = col;
|
||||||
|
}
|
13
examples/iotdashboard/shaders/boxshadow.vert
Normal file
13
examples/iotdashboard/shaders/boxshadow.vert
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
uniform highp mat4 matrix;
|
||||||
|
uniform lowp vec2 aspect;
|
||||||
|
|
||||||
|
attribute highp vec4 in_vertex;
|
||||||
|
attribute mediump vec2 in_coord;
|
||||||
|
|
||||||
|
varying mediump vec2 coord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
coord = in_coord;
|
||||||
|
gl_Position = matrix * in_vertex;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user