Merge branch 'master' into features/effectnode

This commit is contained in:
Uwe Rathmann 2024-01-08 16:09:35 +01:00
commit d397e4f26a
43 changed files with 1397 additions and 213 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
github: [uwerat]

View File

@ -35,9 +35,11 @@ It might support all versions Qt >= 5.15, but you can rely on:
- current long term supported ( LTS ) version of Qt ( at the moment Qt 6.5.x )
- current version of Qt
On debian bullseye these packages need to be installed for Qt5: `build-essential
qtbase5-dev qtbase5-private-dev qtdeclarative5-dev qtdeclarative5-private-dev libqt5svg5-dev`.
For Qt6 you need the corresponding ones.
On Debian these packages need to be installed for Qt6: `build-essential cmake
qtbase6-dev qtbase6-private-dev qtdeclarative6-dev qtdeclarative6-private-dev libqt6svg-dev qt6-shadertools`
For Qt5 you need: `build-essential cmake
qtbase5-dev qtbase5-private-dev qtdeclarative5-dev qtdeclarative5-private-dev libqt5svg-dev`.
> Optional: When enabling the `hunspell` feature the following package needs to be installed: `libhunspell-dev`

View File

@ -5,12 +5,20 @@
macro(qsk_setup_Qt)
# Often users have several Qt installations on their system and
# need to be able to explicitly the one to be used. Let's see if
# standard cmake features are good enough or if we need to introduce
# something sort of additional option. TODO ...
# Use QSK_QT_VERSION specified with baseline 5.15
# otherwise fallback to latest known supported Qt version gte 5.15
# set vars for correct alpha descending sort order and direction (ex. Qt6, Qt5)
if ( NOT QSK_QT_VERSION ) # QSK_QT_VERSION=Qt5
set(QSK_QT_VERSION Qt6 Qt5)
set(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
endif()
find_package(QT "5.15" NAMES ${QSK_QT_VERSION} REQUIRED COMPONENTS Quick)
find_package(QT "5.15" NAMES Qt6 Qt5 REQUIRED COMPONENTS Quick)
if(QT_VERSION_MAJOR VERSION_GREATER_EQUAL 6)
# we need the qsb tool for Qt6
find_package(Qt6 REQUIRED COMPONENTS ShaderTools)
endif()
if ( QT_FOUND )

View File

@ -0,0 +1,109 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "ArcPage.h"
#include "ShadowedArc.h"
#include "Slider.h"
#include <QskGridBox.h>
namespace
{
class ControlPanel : public QskGridBox
{
Q_OBJECT
public:
ControlPanel( ShadowedArc* arc, QQuickItem* parent = nullptr )
: QskGridBox( parent )
{
setMargins( 5 );
setSpacing( 10 );
{
auto slider = new Slider( "Start", 0, 360, 10, arc->startAngle() );
connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setStartAngle );
addItem( slider, 0, 0 );
}
{
auto slider = new Slider( "Span", -360, 360, 10, arc->spanAngle() );
connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setSpanAngle );
addItem( slider, 0, 1 );
}
{
auto slider = new Slider( "Extent", 0, 100, 1, arc->thickness() );
connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setThickness );
addItem( slider, 1, 0 );
}
{
auto slider = new Slider( "Border", 0, 10, 1, arc->borderWidth() );
connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setBorderWidth );
addItem( slider, 1, 1);
}
{
auto slider = new Slider( "Spread Radius", -10, 50, 1, arc->spreadRadius() );
connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setSpreadRadius );
addItem( slider, 2, 0 );
}
{
auto slider = new Slider( "Blur Radius", 0, 50, 1, arc->blurRadius() );
connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setBlurRadius );
addItem( slider, 2, 1 );
}
{
auto slider = new Slider( "Offset X", -50, 50, 1, arc->offsetX() );
connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setOffsetX );
addItem( slider, 3, 0 );
}
{
auto slider = new Slider( "Offset Y", -50, 50, 1, arc->offsetY() );
connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setOffsetY );
addItem( slider, 3, 1 );
}
}
};
}
ArcPage::ArcPage( QQuickItem* parent )
: QskLinearBox( Qt::Vertical, parent )
{
auto arc = new ShadowedArc();
arc->setMargins( 40 ); // some extra space for testing the offsets
{
// initial settings
arc->setStartAngle( 45.0 );
arc->setSpanAngle( 270.0 );
arc->setThickness( 10.0 );
arc->setFillColor( Qt::darkRed );
arc->setBorderWidth( 0 );
arc->setBorderColor( Qt::darkYellow );
arc->setShadowColor( Qt::black );
arc->setSpreadRadius( 0.0 );
arc->setBlurRadius( 4.0 );
arc->setOffsetX( 2.0 );
arc->setOffsetY( 2.0 );
}
auto panel = new ControlPanel( arc );
panel->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed );
addItem( panel );
addItem( arc );
}
#include "ArcPage.moc"

View File

@ -0,0 +1,14 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskLinearBox.h>
class ArcPage : public QskLinearBox
{
public:
ArcPage( QQuickItem* parent = nullptr );
};

View File

@ -0,0 +1,73 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "BoxPage.h"
#include "ShadowedBox.h"
#include "Slider.h"
#include <QskRgbValue.h>
#include <QFontMetrics>
namespace
{
class ControlPanel : public QskLinearBox
{
public:
ControlPanel( ShadowedBox* box, QQuickItem* parent = nullptr )
: QskLinearBox( Qt::Vertical, parent )
{
{
auto slider = new Slider( "Offset X", -50, 50, 1, box->offsetX() );
connect( slider, &Slider::valueChanged, box, &ShadowedBox::setOffsetX );
addItem( slider );
}
{
auto slider = new Slider( "Offset Y", -50, 50, 1, box->offsetY() );
connect( slider, &Slider::valueChanged, box, &ShadowedBox::setOffsetY );
addItem( slider );
}
{
auto slider = new Slider( "Spread Radius", -10, 50, 1, box->spreadRadius() );
connect( slider, &Slider::valueChanged, box, &ShadowedBox::setSpreadRadius );
addItem( slider );
}
{
auto slider = new Slider( "Blur Radius", 0, 50, 1, box->blurRadius() );
connect( slider, &Slider::valueChanged, box, &ShadowedBox::setBlurRadius );
addItem( slider );
}
{
auto slider = new Slider( "Opacity", 0, 1, 0.01, box->opacity() );
connect( slider, &Slider::valueChanged, box, &ShadowedBox::setOpacity );
addItem( slider );
}
}
};
}
BoxPage::BoxPage( QQuickItem* parent )
: QskLinearBox( Qt::Vertical, parent )
{
auto box = new ShadowedBox();
box->setMargins( 40 ); // some extra space for testing the offsets
{
box->setOffsetX( 10 );
box->setOffsetY( 10 );
box->setSpreadRadius( 0 );
box->setBlurRadius( 5 );
}
auto panel = new ControlPanel( box );
panel->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed );
addItem( panel );
addItem( box );
}

View File

@ -0,0 +1,19 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskLinearBox.h>
class QskSlider;
class BoxPage : public QskLinearBox
{
public:
BoxPage( QQuickItem* parent = nullptr );
private:
void addSlider( int row, const QString&, QskSlider* );
};

View File

@ -3,4 +3,7 @@
# SPDX-License-Identifier: BSD-3-Clause
############################################################################
qsk_add_example(shadows ShadowedBox.h ShadowedBox.cpp main.cpp)
qsk_add_example(shadows
BoxPage.h BoxPage.cpp ShadowedBox.h ShadowedBox.cpp
ArcPage.h ArcPage.cpp ShadowedArc.h ShadowedArc.cpp
Slider.h Slider.cpp main.cpp)

View File

@ -0,0 +1,269 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "ShadowedArc.h"
#include <QskSkinlet.h>
#include <QskArcNode.h>
#include <QskArcMetrics.h>
#include <QskShadowMetrics.h>
#include <QskArcNode.h>
#include <QskSGNode.h>
QSK_SUBCONTROL( ShadowedArc, Arc )
namespace
{
class Skinlet : public QskSkinlet
{
using Inherited = QskSkinlet;
public:
enum NodeRoles { ArcRole };
Skinlet( QskSkin* skin = nullptr );
QRectF subControlRect( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol ) const override;
QSGNode* updateSubNode( const QskSkinnable*,
quint8 nodeRole, QSGNode* ) const override;
private:
QSGNode* updateArcNode( const ShadowedArc*, QSGNode* node ) const;
};
Skinlet::Skinlet( QskSkin* skin )
: QskSkinlet( skin )
{
setNodeRoles( { ArcRole } );
}
QRectF Skinlet::subControlRect( const QskSkinnable* skinnable,
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
{
if ( subControl == ShadowedArc::Arc )
return contentsRect;
return Inherited::subControlRect( skinnable, contentsRect, subControl );
}
QSGNode* Skinlet::updateSubNode(
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
{
if ( nodeRole == ArcRole )
{
auto arc = static_cast< const ShadowedArc* >( skinnable );
return updateArcNode( arc, node );
}
return Inherited::updateSubNode( skinnable, nodeRole, node );
}
QSGNode* Skinlet::updateArcNode( const ShadowedArc* arc, QSGNode* node ) const
{
using Q = ShadowedArc;
const auto rect = arc->subControlRect( Q::Arc );
if ( rect.isEmpty() )
return nullptr;
auto arcNode = QskSGNode::ensureNode< QskArcNode >( node );
const auto metrics = arc->arcMetricsHint( Q::Arc );
const auto fillGradient = arc->gradientHint( Q::Arc );
const auto borderColor = arc->color( Q::Arc | QskAspect::Border );
const auto borderWidth = arc->metric( Q::Arc | QskAspect::Border );
const auto shadowColor = arc->shadowColorHint( Q::Arc );
const auto shadowMetrics = arc->shadowMetricsHint( Q::Arc );
arcNode->setArcData( rect, metrics, borderWidth, borderColor,
fillGradient, shadowColor, shadowMetrics);
return arcNode;
}
}
ShadowedArc::ShadowedArc( QQuickItem* parent )
: Inherited( parent )
{
auto skinlet = new Skinlet();
skinlet->setOwnedBySkinnable( true );
setSkinlet( skinlet );
// initial settings
setArcMetrics( { 0.0, 360.0, 1.0, Qt::RelativeSize } );
setFillColor( Qt::darkRed );
setBorderWidth( 0 );
setBorderColor( Qt::gray );
setShadowColor( Qt::black );
setShadowMetrics( { 0, 0, QPointF( 0, 0 ), Qt::AbsoluteSize } );
}
ShadowedArc::~ShadowedArc()
{
}
void ShadowedArc::setThickness( qreal thickness )
{
auto metrics = arcMetrics();
metrics.setThickness( thickness );
setArcMetrics( metrics );
}
qreal ShadowedArc::thickness() const
{
return arcMetrics().thickness();
}
void ShadowedArc::setBorderWidth( qreal width )
{
width = std::max( width, 0.0 );
setMetric( Arc | QskAspect::Border, width );
}
qreal ShadowedArc::borderWidth() const
{
return metric( Arc | QskAspect::Border );
}
void ShadowedArc::setStartAngle( qreal degrees )
{
auto metrics = arcMetrics();
metrics.setStartAngle( degrees );
setArcMetrics( metrics );
}
qreal ShadowedArc::startAngle() const
{
return arcMetrics().startAngle();
}
void ShadowedArc::setSpanAngle( qreal degrees )
{
auto metrics = arcMetrics();
metrics.setSpanAngle( degrees );
setArcMetrics( metrics );
}
qreal ShadowedArc::spanAngle() const
{
return arcMetrics().spanAngle();
}
void ShadowedArc::setOffsetX( qreal dx )
{
auto metrics = shadowMetrics();
metrics.setOffsetX( dx );
setShadowMetrics( metrics );
}
qreal ShadowedArc::offsetX() const
{
return shadowMetrics().offset().x();
}
void ShadowedArc::setOffsetY( qreal dy )
{
auto metrics = shadowMetrics();
metrics.setOffsetY( dy );
setShadowMetrics( metrics );
}
qreal ShadowedArc::offsetY() const
{
return shadowMetrics().offset().y();
}
void ShadowedArc::setSpreadRadius( qreal radius )
{
auto metrics = shadowMetrics();
metrics.setSpreadRadius( radius );
setShadowMetrics( metrics );
}
qreal ShadowedArc::spreadRadius() const
{
return shadowMetrics().spreadRadius();
}
void ShadowedArc::setBlurRadius( qreal radius )
{
auto metrics = shadowMetrics();
metrics.setBlurRadius( radius );
setShadowMetrics( metrics );
}
qreal ShadowedArc::blurRadius() const
{
return shadowMetrics().blurRadius();
}
void ShadowedArc::setFillColor( const QColor& color )
{
setColor( Arc, color );
}
QColor ShadowedArc::fillColor() const
{
return color( Arc );
}
void ShadowedArc::setShadowColor( const QColor& color )
{
setShadowColorHint( Arc, color );
}
QColor ShadowedArc::shadowColor() const
{
return shadowColorHint( Arc );
}
void ShadowedArc::setBorderColor( const QColor& color )
{
setColor( Arc | QskAspect::Border, color );
}
QColor ShadowedArc::borderColor() const
{
return color( Arc | QskAspect::Border );
}
QskShadowMetrics ShadowedArc::shadowMetrics() const
{
return shadowMetricsHint( Arc );
}
void ShadowedArc::setShadowMetrics( const QskShadowMetrics& metrics )
{
setShadowMetricsHint( Arc, metrics );
}
QskArcMetrics ShadowedArc::arcMetrics() const
{
return arcMetricsHint( Arc );
}
void ShadowedArc::setArcMetrics( const QskArcMetrics& metrics )
{
setArcMetricsHint( Arc, metrics );
}
#include "moc_ShadowedArc.cpp"

View File

@ -0,0 +1,64 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskControl.h>
class QskShadowMetrics;
class QskArcMetrics;
class ShadowedArc : public QskControl
{
Q_OBJECT
using Inherited = QskControl;
public:
QSK_SUBCONTROLS( Arc )
ShadowedArc( QQuickItem* parent = nullptr );
~ShadowedArc() override;
qreal thickness() const;
qreal borderWidth() const;
qreal startAngle() const;
qreal spanAngle() const;
qreal offsetX() const;
qreal offsetY() const;
qreal spreadRadius() const;
qreal blurRadius() const;
QColor borderColor() const;
QColor fillColor() const;
QColor shadowColor() const;
public Q_SLOTS:
void setThickness( qreal );
void setBorderWidth( qreal );
void setStartAngle( qreal );
void setSpanAngle( qreal );
void setOffsetX( qreal );
void setOffsetY( qreal );
void setSpreadRadius( qreal );
void setBlurRadius( qreal );
void setBorderColor( const QColor& );
void setFillColor( const QColor& );
void setShadowColor( const QColor& );
private:
QskShadowMetrics shadowMetrics() const;
void setShadowMetrics( const QskShadowMetrics& );
QskArcMetrics arcMetrics() const;
void setArcMetrics( const QskArcMetrics& );
};

View File

@ -14,21 +14,10 @@
ShadowedBox::ShadowedBox( QQuickItem* parentItem )
: QskBox( true, parentItem )
{
QColor c( Qt::darkRed );
#if 0
c.setAlpha( 100 );
#endif
setGradientHint( Panel, c );
setGradientHint( Panel, Qt::darkRed );
setBoxShapeHint( Panel, QskBoxShapeMetrics( 40, 0, 15, 0 ) );
setBoxBorderMetricsHint( Panel, 0 );
#if 0
setBoxBorderMetricsHint( Panel, 10 );
setBoxBorderColorsHint( Panel, Qt::blue );
#endif
setShadowColorHint( Panel, Qt::black );
}

View File

@ -0,0 +1,47 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "Slider.h"
#include <QskSlider.h>
#include <QskTextLabel.h>
#include <qfontmetrics.h>
Slider::Slider( const QString& text, qreal min, qreal max,
qreal step, qreal value, QQuickItem* parent )
: QskLinearBox( Qt::Horizontal, parent )
{
m_label = new QskTextLabel( text, this );
m_label->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed );
m_slider = new QskSlider( this );
m_slider->setBoundaries( min, max );
m_slider->setStepSize( step );
m_slider->setSnap( true );
m_slider->setValue( value );
m_valueLabel = new QskTextLabel( this );
m_valueLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
updateLabel( value );
const QFontMetricsF fm( m_valueLabel->font() );
m_valueLabel->setFixedWidth( fm.horizontalAdvance( "-100" ) );
connect( m_slider, &QskSlider::valueChanged, this, &Slider::updateLabel );
connect( m_slider, &QskSlider::valueChanged, this, &Slider::valueChanged );
}
void Slider::updateLabel( qreal value )
{
m_valueLabel->setText( QString::number( value ) );
}
void Slider::setValue( qreal value )
{
m_slider->setValue( value );
}
#include "moc_Slider.cpp"

View File

@ -0,0 +1,37 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskLinearBox.h>
class QskSlider;
class QskTextLabel;
class Slider : public QskLinearBox
{
Q_OBJECT
using Inherited = QskLinearBox;
public:
Slider( const QString&, qreal min, qreal max, qreal step,
qreal value, QQuickItem* parent = nullptr );
qreal value() const;
Q_SIGNALS:
void valueChanged( qreal );
public Q_SLOTS:
void setValue( qreal );
private:
void updateLabel( qreal );
QskTextLabel* m_label = nullptr;
QskSlider* m_slider = nullptr;
QskTextLabel* m_valueLabel = nullptr;
};

View File

@ -3,129 +3,31 @@
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "ShadowedBox.h"
#include "BoxPage.h"
#include "ArcPage.h"
#include <QskObjectCounter.h>
#include <QskWindow.h>
#include <QskGridBox.h>
#include <QskSlider.h>
#include <QskTextLabel.h>
#include <QskRgbValue.h>
#include <QskTabView.h>
#include <QskTabBar.h>
#include <SkinnyShortcut.h>
#include <QGuiApplication>
#include <QFontMetrics>
class BoxPanel : public QskBox
namespace
{
public:
BoxPanel( QQuickItem* parent = nullptr )
: QskBox( parent )
class TabView : public QskTabView
{
setAutoLayoutChildren( true );
setPadding( 60 );
public:
TabView()
{
//setTabBarEdge( Qt::LeftEdge );
setPanel( true );
setGradientHint( QskBox::Panel, QGradient::SnowAgain );
}
};
class Slider : public QskSlider
{
public:
Slider( qreal min, qreal max, qreal step, qreal value, QQuickItem* parent = nullptr )
: QskSlider( parent )
{
setBoundaries( min, max );
setStepSize( step );
setSnap( true );
setValue( value );
}
};
class ValueLabel : public QskTextLabel
{
public:
ValueLabel( QQuickItem* parent = nullptr )
: QskTextLabel( parent )
{
setFixedWidth( QFontMetrics( font() ).horizontalAdvance( "-100" ) );
setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
}
void setValue( qreal value )
{
setText( QString::number( value ) );
}
};
class GridBox : public QskGridBox
{
public:
GridBox( QQuickItem* parent = nullptr )
: QskGridBox( parent )
{
setPanel( true );
setPadding( 5 );
setColumnStretchFactor( 1, 1 );
auto sliderX = new Slider( -50, 50, 1, 10 );
auto sliderY = new Slider( -50, 50, 1, 10 );
auto sliderSpread = new Slider( 0, 50, 1, 0 );
auto sliderBlur = new Slider( 0, 50, 1, 10 );
auto sliderOpacity = new Slider( 0, 1, 0.01, 1 );
auto panel = new BoxPanel();
int row = 0;
addSlider( row++, "Offset X", sliderX );
addSlider( row++, "Offset Y", sliderY );
addSlider( row++, "Spread Radius", sliderSpread );
addSlider( row++, "Blur Radius", sliderBlur );
addSlider( row++, "Opacity", sliderOpacity );
addItem( panel, row, 0, -1, -1 );
auto box = new ShadowedBox( panel );
box->setOffsetX( sliderX->value() );
box->setOffsetY( sliderY->value() );
box->setSpreadRadius( sliderSpread->value() );
box->setBlurRadius( sliderBlur->value() );
box->setOpacity( sliderOpacity->value() );
connect( sliderX, &QskSlider::valueChanged,
box, &ShadowedBox::setOffsetX );
connect( sliderY, &QskSlider::valueChanged,
box, &ShadowedBox::setOffsetY );
connect( sliderSpread, &QskSlider::valueChanged,
box, &ShadowedBox::setSpreadRadius );
connect( sliderBlur, &QskSlider::valueChanged,
box, &ShadowedBox::setBlurRadius );
connect( sliderOpacity, &QskSlider::valueChanged,
box, &ShadowedBox::setOpacity );
}
private:
void addSlider( int row, const QString& text, QskSlider* slider )
{
addItem( new QskTextLabel( text ), row, 0 );
addItem( slider, row, 1 );
auto label = new ValueLabel();
label->setValue( slider->value() );
addItem( label, row, 2 );
connect( slider, &QskSlider::valueChanged,
label, [label]( qreal value ) { label->setText( QString::number( value ) ); } );
}
};
addTab( "Arc Shadow", new ArcPage() );
addTab( "Box Shadow", new BoxPage() );
}
};
}
int main( int argc, char* argv[] )
{
@ -138,7 +40,7 @@ int main( int argc, char* argv[] )
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
QskWindow window;
window.addItem( new GridBox() );
window.addItem( new TabView() );
window.resize( 600, 600 );
window.show();

View File

@ -99,6 +99,7 @@ list(APPEND SOURCES
list(APPEND HEADERS
nodes/QskArcNode.h
nodes/QskArcShadowNode.h
nodes/QskBasicLinesNode.h
nodes/QskBoxNode.h
nodes/QskBoxClipNode.h
@ -138,6 +139,7 @@ list(APPEND PRIVATE_HEADERS
list(APPEND SOURCES
nodes/QskArcNode.cpp
nodes/QskArcShadowNode.cpp
nodes/QskBasicLinesNode.cpp
nodes/QskBoxNode.cpp
nodes/QskBoxClipNode.cpp
@ -171,7 +173,9 @@ list(APPEND SOURCES
nodes/QskVertex.cpp
)
qt_add_resources(SOURCES nodes/shaders.qrc)
if (QT_VERSION_MAJOR VERSION_LESS 6)
qt_add_resources(SOURCES nodes/shaders.qrc)
endif()
list(APPEND HEADERS
controls/QskAbstractButton.h
@ -471,6 +475,49 @@ if(BUILD_QSKDLL)
set_target_properties(${target} PROPERTIES DEFINE_SYMBOL QSK_MAKEDLL)
endif()
if (QT_VERSION_MAJOR VERSION_GREATER_EQUAL 6)
qt6_add_shaders(${target} "qskshaders"
BATCHABLE
PRECOMPILE
#OPTIMIZED
QUIET
PREFIX
"/qskinny/shaders"
FILES
nodes/shaders/arcshadow-vulkan.vert
nodes/shaders/arcshadow-vulkan.frag
nodes/shaders/boxshadow-vulkan.vert
nodes/shaders/boxshadow-vulkan.frag
nodes/shaders/crisplines-vulkan.vert
nodes/shaders/crisplines-vulkan.frag
nodes/shaders/gradientconic-vulkan.vert
nodes/shaders/gradientconic-vulkan.frag
nodes/shaders/gradientlinear-vulkan.vert
nodes/shaders/gradientlinear-vulkan.frag
nodes/shaders/gradientradial-vulkan.vert
nodes/shaders/gradientradial-vulkan.frag
OUTPUTS
arcshadow.vert.qsb
arcshadow.frag.qsb
boxshadow.vert.qsb
boxshadow.frag.qsb
crisplines.vert.qsb
crisplines.frag.qsb
gradientconic.vert.qsb
gradientconic.frag.qsb
gradientlinear.vert.qsb
gradientlinear.frag.qsb
gradientradial.vert.qsb
gradientradial.frag.qsb
)
endif()
target_include_directories(${target} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/common>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/controls>

View File

@ -273,6 +273,25 @@ QskGradientStops qskInterpolatedGradientStops(
return qskInterpolatedStops( from, to, ratio );
}
QColor qskInterpolatedColorAt( const QskGradientStops& stops, qreal pos ) noexcept
{
if ( stops.isEmpty() )
return QColor();
pos = qBound( 0.0, pos, 1.0 );
if ( pos <= stops.first().position() )
return stops.first().color();
for ( int i = 1; i < stops.count(); i++ )
{
if ( pos <= stops[i].position() )
return qskInterpolatedColor( stops, i - 1, i, pos );
}
return stops.last().color();
}
QskGradientStops qskExtractedGradientStops(
const QskGradientStops& stops, qreal from, qreal to )
{
@ -421,4 +440,3 @@ QGradientStops qskToQGradientStops( const QskGradientStops& stops )
return qStops;
}

View File

@ -120,6 +120,8 @@ QSK_EXPORT QDebug operator<<( QDebug, const QskGradientStop& );
typedef QVector< QskGradientStop > QskGradientStops;
QSK_EXPORT QColor qskInterpolatedColorAt( const QskGradientStops&, qreal pos ) noexcept;
QSK_EXPORT bool qskIsMonochrome( const QskGradientStops& ) noexcept;
QSK_EXPORT bool qskIsVisible( const QskGradientStops& ) noexcept;

View File

@ -231,7 +231,7 @@ static inline QSGNode* qskUpdateArcNode(
return nullptr;
auto arcNode = QskSGNode::ensureNode< QskArcNode >( node );
arcNode->setArcData( rect, metrics, borderWidth, borderColor, gradient );
arcNode->setArcData( rect, metrics, borderWidth, borderColor, gradient, {}, {} );
return arcNode;
}
@ -547,11 +547,11 @@ QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
}
QSGNode* QskSkinlet::updateArcNode(
const QskSkinnable* skinnable, QSGNode* node, const QRectF& rect,
const QskSkinnable* skinnable, QSGNode* node, const QRectF& rect,
qreal borderWidth, const QColor& borderColor,
const QskGradient& fillGradient, const QskArcMetrics& metrics )
{
return qskUpdateArcNode( skinnable, node, rect,
return qskUpdateArcNode( skinnable, node, rect,
borderWidth, borderColor, fillGradient, metrics );
}
@ -594,7 +594,7 @@ QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
}
QSGNode* QskSkinlet::updateLineNode( const QskSkinnable* skinnable,
QSGNode* node, const QLineF& line, QskAspect::Subcontrol subControl )
QSGNode* node, const QLineF& line, QskAspect::Subcontrol subControl )
{
auto lineStipple = skinnable->stippleMetricsHint( subControl );
if ( !lineStipple.isValid() )

View File

@ -416,6 +416,20 @@ void QskWindow::keyReleaseEvent( QKeyEvent* event )
void QskWindow::exposeEvent( QExposeEvent* event )
{
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
if ( qskRenderingHardwareInterface( this ) )
{
/*
Actually our code supports Qt5 RHI ( f9c08c34fb2cc64546bbe6ce9d359f416e934961 ),
but Qt5 does not come with the qsb tool out of the box. Then we run into
problems with compiling the shader code from the makefiles.
But why should anyone use the experimental Qt5 RHI implementations
instead of using Qt6 ...
*/
qFatal( "the experimental Qt5 RHI implementation is not supported:\n"
"\tuse Qt6 or run the default OpenGL backend." );
}
#endif
ensureFocus( Qt::OtherFocusReason );
layoutItems();

View File

@ -5,15 +5,27 @@
#include "QskArcNode.h"
#include "QskArcMetrics.h"
#include "QskArcShadowNode.h"
#include "QskMargins.h"
#include "QskGradient.h"
#include "QskShapeNode.h"
#include "QskStrokeNode.h"
#include "QskSGNode.h"
#include "QskShadowMetrics.h"
#include <qpen.h>
#include <qpainterpath.h>
namespace
{
enum NodeRole
{
ShadowRole,
FillRole,
BorderRole
};
}
static inline QskGradient qskEffectiveGradient(
const QskGradient& gradient, const QskArcMetrics& metrics )
{
@ -54,6 +66,14 @@ static inline QRectF qskEffectiveRect(
return qskValidOrEmptyInnerRect( rect, QskMargins( 0.5 * borderWidth ) );
}
static void qskUpdateChildren( QSGNode* parentNode, quint8 role, QSGNode* node )
{
static const QVector< quint8 > roles = { ShadowRole, FillRole, BorderRole };
auto oldNode = QskSGNode::findChildNode( parentNode, role );
QskSGNode::replaceChildNode( roles, role, parentNode, oldNode, node );
}
QskArcNode::QskArcNode()
{
}
@ -65,20 +85,24 @@ QskArcNode::~QskArcNode()
void QskArcNode::setArcData( const QRectF& rect,
const QskArcMetrics& arcMetrics, const QskGradient& fillGradient )
{
setArcData( rect, arcMetrics, 0.0, QColor(), fillGradient );
setArcData( rect, arcMetrics, 0.0, QColor(), fillGradient, {}, {} );
}
void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics,
qreal borderWidth, const QColor& borderColor, const QskGradient& fillGradient )
const qreal borderWidth, const QColor& borderColor, const QskGradient& fillGradient )
{
enum NodeRole
{
FillRole,
BorderRole
};
setArcData( rect, arcMetrics, borderWidth, borderColor, fillGradient, {}, {} );
}
const auto metrics = qskEffectiveMetrics( arcMetrics, rect );
const auto gradient = qskEffectiveGradient( fillGradient, metrics );
void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics,
const qreal borderWidth, const QColor& borderColor, const QskGradient& fillGradient,
const QColor& shadowColor, const QskShadowMetrics& shadowMetrics )
{
const auto metricsArc = qskEffectiveMetrics( arcMetrics, rect );
const auto gradient = qskEffectiveGradient( fillGradient, metricsArc );
auto shadowNode = static_cast< QskArcShadowNode* >(
QskSGNode::findChildNode( this, ShadowRole ) );
auto fillNode = static_cast< QskShapeNode* >(
QskSGNode::findChildNode( this, FillRole ) );
@ -89,22 +113,52 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
const auto arcRect = qskEffectiveRect( rect, borderWidth );
if ( arcRect.isEmpty() )
{
delete shadowNode;
delete fillNode;
delete borderNode;
return;
}
const auto path = metrics.painterPath( arcRect );
const auto isFillNodeVisible = gradient.isVisible() && !metricsArc.isNull();
const auto isStrokeNodeVisible = borderWidth > 0.0 && borderColor.alpha() > 0;
const auto isShadowNodeVisible = shadowColor.alpha() > 0.0 && isFillNodeVisible;
if ( gradient.isVisible() && !metrics.isNull() )
const auto path = metricsArc.painterPath( arcRect );
if ( isShadowNodeVisible )
{
if ( shadowNode == nullptr )
{
shadowNode = new QskArcShadowNode;
QskSGNode::setNodeRole( shadowNode, ShadowRole );
}
/*
The shader of the shadow node is for circular arcs and we have some
unwanted scaling issues for the spread/blur values when having ellipsoid
arcs. We might also want to add the spread value to the ends of the arc
and not only to its radius. TODO ...
*/
const auto sm = shadowMetrics.toAbsolute( arcRect.size() );
const auto shadowRect = sm.shadowRect( arcRect );
const auto spreadRadius = sm.spreadRadius() + 0.5 * metricsArc.thickness();
shadowNode->setShadowData( shadowRect, spreadRadius, sm.blurRadius(),
metricsArc.startAngle(), metricsArc.spanAngle(), shadowColor );
}
else
{
delete shadowNode;
shadowNode = nullptr;
}
if ( isFillNodeVisible )
{
if ( fillNode == nullptr )
{
fillNode = new QskShapeNode;
QskSGNode::setNodeRole( fillNode, FillRole );
prependChildNode( fillNode );
}
fillNode->updateNode( path, QTransform(), arcRect, gradient );
@ -112,25 +166,29 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
else
{
delete fillNode;
fillNode = nullptr;
}
if ( borderWidth > 0.0 && borderColor.alpha() > 0 )
if ( isStrokeNodeVisible )
{
if ( borderNode == nullptr )
{
borderNode = new QskStrokeNode;
QskSGNode::setNodeRole( borderNode, BorderRole );
appendChildNode( borderNode );
}
QPen pen( borderColor, borderWidth );
pen.setCapStyle( Qt::FlatCap );
borderNode->updateNode( path, QTransform(), pen );
}
else
{
delete borderNode;
borderNode = nullptr;
}
qskUpdateChildren(this, ShadowRole, shadowNode);
qskUpdateChildren(this, FillRole, fillNode);
qskUpdateChildren(this, BorderRole, borderNode);
}

View File

@ -10,6 +10,7 @@
class QskArcMetrics;
class QskGradient;
class QskShadowMetrics;
/*
For the moment a QPainterPath/QskShapeNode.
@ -23,8 +24,13 @@ class QSK_EXPORT QskArcNode : public QskShapeNode
~QskArcNode() override;
void setArcData( const QRectF&, const QskArcMetrics&, const QskGradient& );
void setArcData( const QRectF&, const QskArcMetrics&,
qreal borderWidth, const QColor& borderColor, const QskGradient& );
void setArcData( const QRectF&, const QskArcMetrics&,
qreal borderWidth, const QColor& borderColor, const QskGradient&,
const QColor& shadowColor, const QskShadowMetrics&);
};
#endif

View File

@ -0,0 +1,368 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskArcShadowNode.h"
#include <qcolor.h>
#include <qsgmaterial.h>
#include <qsgmaterialshader.h>
#include <qmath.h>
#include <cstring>
QSK_QT_PRIVATE_BEGIN
#include <private/qsgnode_p.h>
QSK_QT_PRIVATE_END
// QSGMaterialRhiShader became QSGMaterialShader in Qt6
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
#include <QSGMaterialRhiShader>
using RhiShader = QSGMaterialRhiShader;
#else
using RhiShader = QSGMaterialShader;
#endif
namespace
{
class Material final : public QSGMaterial
{
public:
Material();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QSGMaterialShader* createShader() const override;
#else
QSGMaterialShader* createShader( QSGRendererInterface::RenderMode ) const override;
#endif
QSGMaterialType* type() const override;
int compare( const QSGMaterial* other ) const override;
QVector4D m_color { 0, 0, 0, 1 };
QVector4D m_arc = {};
float m_spreadRadius = 0.0f;
float m_blurRadius = 0.0f;
};
}
namespace
{
class ShaderRhi final : public RhiShader
{
public:
ShaderRhi()
{
const QString root( ":/qskinny/shaders/" );
setShaderFileName( VertexStage, root + "arcshadow.vert.qsb" );
setShaderFileName( FragmentStage, root + "arcshadow.frag.qsb" );
}
bool updateUniformData( RenderState& state,
QSGMaterial* const newMaterial, QSGMaterial* const oldMaterial ) override
{
const auto matOld = static_cast< Material* >( oldMaterial );
const auto matNew = static_cast< Material* >( newMaterial );
Q_ASSERT( state.uniformData()->size() == 108 );
auto data = state.uniformData()->data();
bool changed = false;
if ( state.isMatrixDirty() )
{
const auto matrix = state.combinedMatrix();
memcpy( data + 0, matrix.constData(), 64 );
changed = true;
}
if ( matOld == nullptr || matNew->m_color != matOld->m_color )
{
memcpy( data + 64, &matNew->m_color, 16 );
changed = true;
}
if ( matOld == nullptr || matNew->m_arc != matOld->m_arc )
{
memcpy( data + 80, &matNew->m_arc, 16 );
changed = true;
}
if ( matOld == nullptr || matNew->m_spreadRadius != matOld->m_spreadRadius )
{
memcpy( data + 96, &matNew->m_spreadRadius, 4 );
changed = true;
}
if ( matOld == nullptr || matNew->m_blurRadius != matOld->m_blurRadius )
{
memcpy( data + 100, &matNew->m_blurRadius, 4 );
changed = true;
}
if ( state.isOpacityDirty() )
{
const float opacity = state.opacity();
memcpy( data + 104, &opacity, 4 );
changed = true;
}
return changed;
}
};
}
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
namespace
{
// the old type of shader - specific for OpenGL
class ShaderGL final : public QSGMaterialShader
{
struct Uniforms
{
int matrix = -1;
int color = -1;
int arc = -1;
int spreadRadius = -1;
int blurRadius = -1;
int opacity = -1;
};
public:
ShaderGL()
{
const QString root( ":/qskinny/shaders/" );
setShaderSourceFile( QOpenGLShader::Vertex, root + "arcshadow.vert" );
setShaderSourceFile( QOpenGLShader::Fragment, root + "arcshadow.frag" );
}
char const* const* attributeNames() const override
{
static char const* const names[] = { "in_vertex", "in_coord", nullptr };
return names;
}
void initialize() override
{
QSGMaterialShader::initialize();
const auto* const p = program();
id.matrix = p->uniformLocation( "matrix" );
id.color = p->uniformLocation( "color" );
id.arc = p->uniformLocation( "arc" );
id.spreadRadius = p->uniformLocation( "spreadRadius" );
id.blurRadius = p->uniformLocation( "blurRadius" );
id.opacity = p->uniformLocation( "opacity" );
}
void updateState( const QSGMaterialShader::RenderState& state,
QSGMaterial* const newMaterial, QSGMaterial* const oldMaterial ) override
{
auto* const p = program();
if ( state.isMatrixDirty() )
{
p->setUniformValue( id.matrix, state.combinedMatrix() );
}
if ( state.isOpacityDirty() )
{
p->setUniformValue( id.opacity, state.opacity() );
}
auto updateMaterial = ( oldMaterial == nullptr ) ||
( newMaterial->compare( oldMaterial ) != 0 );
updateMaterial |= state.isCachedMaterialDataDirty();
if ( updateMaterial )
{
const auto* const material = static_cast< const Material* >( newMaterial );
p->setUniformValue( id.color, material->m_color );
p->setUniformValue( id.arc, material->m_arc );
p->setUniformValue( id.spreadRadius, material->m_spreadRadius );
p->setUniformValue( id.blurRadius, material->m_blurRadius );
}
}
private:
Uniforms id;
};
}
#endif
namespace
{
Material::Material()
{
setFlag( QSGMaterial::Blending, true );
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
setFlag( QSGMaterial::SupportsRhiShader, true );
#endif
}
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QSGMaterialShader* Material::createShader() const
{
if ( !( flags() & QSGMaterial::RhiShaderWanted ) )
return new ShaderGL();
return new ShaderRhi();
}
#else
QSGMaterialShader* Material::createShader( QSGRendererInterface::RenderMode ) const
{
return new ShaderRhi();
}
#endif
QSGMaterialType* Material::type() const
{
static QSGMaterialType staticType;
return &staticType;
}
int Material::compare( const QSGMaterial* const other ) const
{
auto material = static_cast< const Material* >( other );
if ( ( material->m_color == m_color )
&& ( material->m_arc == m_arc )
&& qFuzzyCompare( material->m_spreadRadius, m_spreadRadius )
&& qFuzzyCompare( material->m_blurRadius, m_blurRadius ) )
{
return 0;
}
return QSGMaterial::compare( other );
}
}
class QskArcShadowNodePrivate final : public QSGGeometryNodePrivate
{
public:
QskArcShadowNodePrivate()
: geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 )
{
}
QSGGeometry geometry;
Material material;
QRectF rect;
};
QskArcShadowNode::QskArcShadowNode()
: QSGGeometryNode( *new QskArcShadowNodePrivate )
{
Q_D( QskArcShadowNode );
setGeometry( &d->geometry );
setMaterial( &d->material );
d->geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
d->material.setFlag( QSGMaterial::Blending );
}
QskArcShadowNode::~QskArcShadowNode() = default;
void QskArcShadowNode::setShadowData(
const QRectF& rect, qreal spreadRadius, qreal blurRadius,
qreal startAngle, qreal spanAngle, const QColor& color )
{
if ( qFuzzyIsNull( spanAngle ) || color.alpha() == 0 )
{
setBoundingRectangle( {} );
return;
}
Q_D( QskArcShadowNode );
if ( d->rect != rect )
{
setBoundingRectangle( rect ); // bounding rectangle includig spread/blur
}
const auto size = qMin( rect.width(), rect.height() );
{
#if 1
const auto a = color.alphaF();
const QVector4D c( color.redF() * a, color.greenF() * a, color.blueF() * a, a );
#else
const QVector4D c( color.redF(), color.greenF(), color.blueF(), color.alphaF() );
#endif
if ( d->material.m_color != c )
{
d->material.m_color = c;
markDirty( QSGNode::DirtyMaterial );
}
}
{
const float r = spreadRadius / size;
if ( d->material.m_spreadRadius != r )
{
d->material.m_spreadRadius = r;
markDirty( QSGNode::DirtyMaterial );
}
}
{
const float r = blurRadius / size;
if ( d->material.m_blurRadius != r )
{
d->material.m_blurRadius = r;
markDirty( QSGNode::DirtyMaterial );
}
}
{
QVector4D arc( 0.0, 0.0, 1.0, 0.0 );
{
const auto a1 = qDegreesToRadians( startAngle + 0.5 * spanAngle );
const auto a2 = qDegreesToRadians( 0.5 * qAbs( spanAngle ) );
arc = QVector4D( ::cos( a1 ), ::sin( a1 ), ::cos( a2 ), ::sin( a2 ) );
}
if ( d->material.m_arc != arc )
{
d->material.m_arc = arc;
markDirty( QSGNode::DirtyMaterial );
}
}
}
void QskArcShadowNode::setBoundingRectangle( const QRectF& rect )
{
Q_D( QskArcShadowNode );
if ( d->rect == rect )
return;
d->rect = rect;
QSGGeometry::updateTexturedRectGeometry(
&d->geometry, d->rect, { -0.5, -0.5, 1.0, 1.0 } );
d->geometry.markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
}

View File

@ -0,0 +1,32 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_ARC_SHADOW_NODE_H
#define QSK_ARC_SHADOW_NODE_H
#include "QskGlobal.h"
#include <qsgnode.h>
class QskArcMetrics;
class QskShadowMetrics;
class QskArcShadowNodePrivate;
class QskArcShadowNode : public QSGGeometryNode
{
public:
QskArcShadowNode();
~QskArcShadowNode() override;
void setShadowData( const QRectF&, qreal spreadRadius, qreal blurRadius,
qreal startAngle, qreal spanAngle, const QColor& );
private:
void setBoundingRectangle( const QRectF& );
Q_DECLARE_PRIVATE( QskArcShadowNode )
};
#endif

View File

@ -40,7 +40,7 @@ namespace
int compare( const QSGMaterial* other ) const override;
QVector2D m_aspect = QVector2D{ 1, 1 };
QVector2D m_aspectRatio = QVector2D{ 1, 1 };
QVector4D m_radius = QVector4D{ 0, 0, 0, 0 };
QVector4D m_color = QVector4D{ 0, 0, 0, 1 };
float m_blurExtent = 0.0;
@ -91,9 +91,9 @@ namespace
changed = true;
}
if ( matOld == nullptr || matNew->m_aspect != matOld->m_aspect )
if ( matOld == nullptr || matNew->m_aspectRatio != matOld->m_aspectRatio )
{
memcpy( data + 96, &matNew->m_aspect, 8 );
memcpy( data + 96, &matNew->m_aspectRatio, 8 );
changed = true;
}
@ -146,7 +146,7 @@ namespace
auto p = program();
m_matrixId = p->uniformLocation( "matrix" );
m_aspectId = p->uniformLocation( "aspect" );
m_aspectRatioId = p->uniformLocation( "aspectRatio" );
m_opacityId = p->uniformLocation( "opacity" );
m_blurExtentId = p->uniformLocation( "blurExtent" );
m_radiusId = p->uniformLocation( "radius" );
@ -173,7 +173,7 @@ namespace
{
auto material = static_cast< const Material* >( newMaterial );
p->setUniformValue( m_aspectId, material->m_aspect );
p->setUniformValue( m_aspectRatioId, material->m_aspectRatio );
p->setUniformValue( m_blurExtentId, material->m_blurExtent);
p->setUniformValue( m_radiusId, material->m_radius );
p->setUniformValue( m_colorId, material->m_color );
@ -183,7 +183,7 @@ namespace
private:
int m_matrixId = -1;
int m_opacityId = -1;
int m_aspectId = -1;
int m_aspectRatioId = -1;
int m_blurExtentId = -1;
int m_radiusId = -1;
int m_colorId = -1;
@ -231,7 +231,7 @@ int Material::compare( const QSGMaterial* other ) const
auto material = static_cast< const Material* >( other );
if ( ( material->m_color == m_color )
&& ( material->m_aspect == m_aspect )
&& ( material->m_aspectRatio == m_aspectRatio )
&& qFuzzyCompare(material->m_blurExtent, m_blurExtent)
&& qFuzzyCompare(material->m_radius, m_radius) )
{
@ -284,16 +284,16 @@ void QskBoxShadowNode::setShadowData(
d->geometry.markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
QVector2D aspect( 1.0, 1.0 );
QVector2D aspectRatio( 1.0, 1.0 );
if ( rect.width() >= rect.height() )
aspect.setX( rect.width() / rect.height() );
aspectRatio.setX( rect.width() / rect.height() );
else
aspect.setY( rect.height() / rect.width() );
aspectRatio.setY( rect.height() / rect.width() );
if ( d->material.m_aspect != aspect )
if ( d->material.m_aspectRatio != aspectRatio )
{
d->material.m_aspect = aspect;
d->material.m_aspectRatio = aspectRatio;
markDirty( QSGNode::DirtyMaterial );
}
}

View File

@ -2,28 +2,21 @@
<RCC version="1.0">
<qresource prefix="/qskinny/">
<file>shaders/boxshadow.vert.qsb</file>
<file>shaders/boxshadow.frag.qsb</file>
<file>shaders/arcshadow.vert</file>
<file>shaders/arcshadow.frag</file>
<file>shaders/boxshadow.vert</file>
<file>shaders/boxshadow.frag</file>
<file>shaders/gradientconic.vert.qsb</file>
<file>shaders/gradientconic.frag.qsb</file>
<file>shaders/gradientconic.vert</file>
<file>shaders/gradientconic.frag</file>
<file>shaders/gradientradial.vert.qsb</file>
<file>shaders/gradientradial.frag.qsb</file>
<file>shaders/gradientradial.vert</file>
<file>shaders/gradientradial.frag</file>
<file>shaders/gradientlinear.vert.qsb</file>
<file>shaders/gradientlinear.frag.qsb</file>
<file>shaders/gradientlinear.vert</file>
<file>shaders/gradientlinear.frag</file>
<file>shaders/crisplines.vert.qsb</file>
<file>shaders/crisplines.frag.qsb</file>
<file>shaders/crisplines.vert</file>
</qresource>

View File

@ -0,0 +1,46 @@
#version 440
layout( location = 0 ) in vec2 coord;
layout( location = 0 ) out vec4 fragColor;
layout( std140, binding = 0 ) uniform buf
{
mat4 matrix;
vec4 color;
/*
arc.xy: cos/sin of the angle of the midpoint
arc.zw: cos/sin of the angle between midpoint/endpoint
*/
vec4 arc;
float spreadRadius;
float blurRadius;
float opacity;
} ubuf;
mat2 rotation( vec2 v ) { return mat2( v.x, -v.y, v.y, v.x ); }
void main()
{
float radius = 0.5 - ubuf.blurRadius - ubuf.spreadRadius;
float dist = abs( length( coord ) - radius ) - ubuf.spreadRadius;
if ( ( ubuf.arc.z ) < 1.0 && ( dist < 1.0 ) )
{
vec2 v = coord * rotation( ubuf.arc.xy ); // x-axial symmetric
v.y = abs( v.y );
v *= rotation ( ubuf.arc.wz ); // end point to 90°
if ( v.x < 0.0 )
{
v.y = max( 0.0, abs( v.y - radius ) - ubuf.spreadRadius );
dist = max( dist, length( v ) );
}
}
float a = 1.0 - smoothstep( 0.0, ubuf.blurRadius, dist );
fragColor = ubuf.color * a * ubuf.opacity;
}

View File

@ -0,0 +1,21 @@
#version 440
layout( location = 0 ) in vec4 in_vertex;
layout( location = 1 ) in vec2 in_coord;
layout( location = 0 ) out vec2 coord;
layout( std140, binding = 0 ) uniform buf
{
mat4 matrix;
vec4 color;
vec4 arc;
float spreadRadius;
float blurRadius;
float opacity;
} ubuf;
void main()
{
coord = in_coord;
gl_Position = ubuf.matrix * in_vertex;
}

View File

@ -0,0 +1,37 @@
varying lowp vec2 coord;
uniform lowp vec4 color;
uniform lowp float spreadRadius;
uniform lowp float blurRadius;
uniform lowp float opacity;
/*
arc.xy: cos/sin of the angle of the midpoint
arc.zw: cos/sin of the angle between midpoint/endpoint
*/
uniform lowp vec4 arc;
mat2 rotation( vec2 v ) { return mat2( v.x, -v.y, v.y, v.x ); }
void main()
{
float radius = 0.5 - blurRadius - spreadRadius;
float dist = abs( length( coord ) - radius ) - spreadRadius;
if ( ( arc.z < 1.0 ) && ( dist < 1.0 ) )
{
vec2 v = coord * rotation( arc.xy ); // x-axial symmetric
v.y = abs( v.y );
v *= rotation( arc.wz ); // end point at 90°
if ( v.x < 0.0 )
{
v.y = max( 0.0, abs( v.y - radius ) - spreadRadius );
dist = max( dist, length( v ) );
}
}
float a = 1.0 - smoothstep( 0.0, blurRadius, dist );
gl_FragColor = color * a * opacity;
}

View File

@ -0,0 +1,12 @@
uniform highp mat4 matrix;
attribute highp vec4 in_vertex;
attribute mediump vec2 in_coord;
varying mediump vec2 coord;
void main()
{
coord = in_coord;
gl_Position = matrix * in_vertex;
}

View File

@ -8,7 +8,7 @@ layout( std140, binding = 0 ) uniform buf
mat4 matrix;
vec4 color;
vec4 radius;
vec2 aspect;
vec2 aspectRatio;
float blurExtent;
float opacity;
} ubuf;
@ -25,25 +25,21 @@ void main()
{
vec4 col = vec4(0.0);
if ( ubuf.opacity > 0.0 )
{
const float minRadius = 0.05;
float e2 = 0.5 * ubuf.blurExtent;
float r = 2.0 * effectiveRadius( ubuf.radius, coord );
float e2 = 0.5 * ubuf.blurExtent;
float r = 2.0 * effectiveRadius( ubuf.radius, coord );
const float minRadius = 0.05;
float f = minRadius / max( r, minRadius );
float f = minRadius / max( r, minRadius );
r += e2 * f;
r += e2 * f;
vec2 d = r + ubuf.blurExtent - ubuf.aspectRatio * ( 1.0 - abs( 2.0 * coord ) );
float l = min( max(d.x, d.y), 0.0) + length( max(d, 0.0) );
vec2 d = r + ubuf.blurExtent - ubuf.aspect * ( 1.0 - abs( 2.0 * coord ) );
float l = min( max(d.x, d.y), 0.0) + length( max(d, 0.0) );
float shadow = l - r;
float shadow = l - r;
float v = smoothstep( -e2, e2, shadow );
col = mix( ubuf.color, vec4(0.0), v ) * ubuf.opacity;
}
float v = smoothstep( -e2, e2, shadow );
col = mix( ubuf.color, vec4(0.0), v ) * ubuf.opacity;
fragColor = col;
}

View File

@ -10,7 +10,7 @@ layout( std140, binding = 0 ) uniform buf
mat4 matrix;
vec4 color;
vec4 radius;
vec2 aspect;
vec2 aspectRatio;
float blurExtent;
float opacity;
} ubuf;

View File

@ -2,7 +2,7 @@ uniform lowp float opacity;
uniform lowp float blurExtent;
uniform lowp vec4 radius;
uniform lowp vec4 color;
uniform lowp vec2 aspect;
uniform lowp vec2 aspectRatio;
varying lowp vec2 coord;
@ -18,25 +18,19 @@ 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 e2 = 0.5 * blurExtent;
lowp float r = 2.0 * effectiveRadius( radius, coord );
const lowp float minRadius = 0.05;
r += e2 * ( minRadius / max( r, minRadius ) );
lowp float f = minRadius / max( r, minRadius );
lowp vec2 d = r + blurExtent - aspectRatio * ( 1.0 - abs( 2.0 * coord ) );
lowp float l = min( max(d.x, d.y), 0.0) + length( max(d, 0.0) );
r += e2 * f;
lowp float shadow = l - r;
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;
}
lowp float v = smoothstep( -e2, e2, shadow );
col = mix( color, vec4(0.0), v ) * opacity;
gl_FragColor = col;
}

Binary file not shown.

Binary file not shown.

View File

@ -6,6 +6,9 @@ function qsbcompile {
# qsb --qt6 -b -o ${qsbfile}.qsb $1
}
qsbcompile arcshadow-vulkan.vert
qsbcompile arcshadow-vulkan.frag
qsbcompile boxshadow-vulkan.vert
qsbcompile boxshadow-vulkan.frag