qskinny/src/nodes/QskArcNode.cpp

149 lines
4.6 KiB
C++
Raw Normal View History

2023-04-06 07:23:37 +00:00
/******************************************************************************
2024-01-17 13:31:45 +00:00
* QSkinny - Copyright (C) The authors
2023-04-06 07:23:37 +00:00
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskArcNode.h"
#include "QskArcMetrics.h"
#include "QskArcShadowNode.h"
2024-09-11 08:24:22 +00:00
#include "QskArcRenderNode.h"
#include "QskArcRenderer.h"
#include "QskMargins.h"
2022-06-01 14:57:57 +00:00
#include "QskGradient.h"
#include "QskSGNode.h"
#include "QskShadowMetrics.h"
2024-09-24 08:14:26 +00:00
#include "QskRgbValue.h"
#include <qpainterpath.h>
2022-06-01 14:57:57 +00:00
namespace
{
enum NodeRole
{
ShadowRole,
2024-09-11 08:24:22 +00:00
2024-09-23 14:04:09 +00:00
/*
If possible border + filling will be displayed by ArcRole
Otherwise ArcRole displays the border and FillRole the filling
*/
ArcRole,
FillRole
};
}
2024-09-23 14:04:09 +00:00
static void qskUpdateChildren( QSGNode* parentNode, quint8 role, QSGNode* node )
2023-04-14 07:47:10 +00:00
{
2024-09-23 14:04:09 +00:00
static const QVector< quint8 > roles = { ShadowRole, ArcRole, FillRole };
2023-04-14 07:47:10 +00:00
2024-09-23 14:04:09 +00:00
auto oldNode = QskSGNode::findChildNode( parentNode, role );
QskSGNode::replaceChildNode( roles, role, parentNode, oldNode, node );
2022-06-01 14:57:57 +00:00
}
2024-09-11 08:24:22 +00:00
template< typename Node >
2024-09-23 14:04:09 +00:00
inline Node* qskNode( QSGNode* parentNode, quint8 role )
{
2024-09-11 08:24:22 +00:00
using namespace QskSGNode;
2024-09-23 14:04:09 +00:00
auto node = static_cast< Node* > ( findChildNode( parentNode, role ) );
2024-09-23 14:04:09 +00:00
if ( node == nullptr )
{
node = new Node();
setNodeRole( node, role );
}
2024-09-23 14:04:09 +00:00
return node;
}
QskArcNode::QskArcNode()
{
}
QskArcNode::~QskArcNode()
{
}
void QskArcNode::setArcData( const QRectF& rect,
2024-09-11 08:24:22 +00:00
const QskArcMetrics& arcMetrics, const QskGradient& gradient )
{
2024-09-11 08:24:22 +00:00
setArcData( rect, arcMetrics, 0.0, QColor(), gradient, {}, {} );
}
void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics,
2024-09-11 08:24:22 +00:00
const qreal borderWidth, const QColor& borderColor, const QskGradient& gradient )
{
2024-09-11 08:24:22 +00:00
setArcData( rect, arcMetrics, borderWidth, borderColor, gradient, {}, {} );
}
void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics,
2024-09-11 08:24:22 +00:00
const qreal borderWidth, const QColor& borderColor, const QskGradient& gradient,
const QColor& shadowColor, const QskShadowMetrics& shadowMetrics )
{
2024-09-23 14:04:09 +00:00
using namespace QskSGNode;
2024-09-23 14:04:09 +00:00
QskArcShadowNode* shadowNode = nullptr;
QskArcRenderNode* arcNode = nullptr;
QskArcRenderNode* fillNode = nullptr;
2024-09-23 14:04:09 +00:00
if ( !( rect.isEmpty() || arcMetrics.isNull() ) )
{
2024-09-23 14:04:09 +00:00
const bool radial = false;
const auto metricsArc = arcMetrics.toAbsolute( rect.size() );
2024-09-23 14:04:09 +00:00
const auto hasFilling = gradient.isVisible();
2024-09-24 08:14:26 +00:00
const auto hasBorder = ( borderWidth > 0.0 ) && QskRgb::isVisible( borderColor );
const auto hasShadow = hasFilling && QskRgb::isVisible( shadowColor );
2024-09-24 08:14:26 +00:00
if ( hasShadow )
2024-09-23 14:04:09 +00:00
{
/*
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 ...
*/
2024-09-23 14:04:09 +00:00
shadowNode = qskNode< QskArcShadowNode >( this, ShadowRole );
2024-09-23 14:04:09 +00:00
const auto sm = shadowMetrics.toAbsolute( rect.size() );
const auto shadowRect = sm.shadowRect( rect );
const auto spreadRadius = sm.spreadRadius() + 0.5 * metricsArc.thickness();
2024-09-23 14:04:09 +00:00
shadowNode->setShadowData( shadowRect, spreadRadius, sm.blurRadius(),
metricsArc.startAngle(), metricsArc.spanAngle(), shadowColor );
}
2024-09-23 14:04:09 +00:00
if ( hasBorder || hasFilling )
{
arcNode = qskNode< QskArcRenderNode >( this, ArcRole );
if ( hasBorder && hasFilling )
{
2024-09-24 08:17:10 +00:00
const bool doCombine = arcNode->hasHint( QskFillNode::PreferColoredGeometry )
&& QskArcRenderer::isGradientSupported( rect, metricsArc, gradient );
if ( !doCombine )
2024-09-23 14:04:09 +00:00
fillNode = qskNode< QskArcRenderNode >( this, FillRole );
}
if ( fillNode )
{
arcNode->updateBorder( rect, metricsArc,
radial, borderWidth, borderColor );
fillNode->updateFilling( rect, metricsArc, radial, borderWidth, gradient );
}
else
{
arcNode->updateArc( rect, metricsArc,
radial, borderWidth, borderColor, gradient );
}
}
}
2024-09-23 14:04:09 +00:00
qskUpdateChildren( this, ShadowRole, shadowNode );
qskUpdateChildren( this, ArcRole, arcNode );
qskUpdateChildren( this, FillRole, fillNode );
}