qskinny/playground/shapes/ShapeItem.cpp

185 lines
4.1 KiB
C++
Raw Normal View History

2022-09-26 17:51:28 +02:00
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "ShapeItem.h"
#include <QskStrokeNode.h>
#include <QskShapeNode.h>
#include <QskSGNode.h>
2022-09-29 16:50:46 +02:00
static inline QTransform transformForRects( const QRectF& r1, const QRectF& r2 )
{
return QTransform::fromTranslate( -r1.x(), -r1.y() )
* QTransform::fromScale( r2.width() / r1.width(), r2.height() / r1.height() )
* QTransform::fromTranslate( r2.x(), r2.y() );
}
static inline bool isVisible( const QColor& color )
{
return color.isValid() && ( color.alpha() > 0 );
}
static inline bool isVisible( const QPen& pen )
{
return ( pen.style() != Qt::NoPen ) && isVisible( pen.color() );
}
2022-09-30 15:09:52 +02:00
static inline qreal effectivePenWidth(
const QPen& pen, const QRectF& r1, const QRectF& r2 )
2022-09-29 16:50:46 +02:00
{
2022-09-30 15:09:52 +02:00
qreal width = pen.widthF();
2022-09-29 16:50:46 +02:00
2022-09-30 15:09:52 +02:00
if ( !pen.isCosmetic() )
{
const qreal sx = r1.width() / r2.width();
const qreal sy = r1.height() / r2.height();
2022-09-29 16:50:46 +02:00
2022-09-30 15:09:52 +02:00
width *= std::min( sx, sy );
}
2022-09-29 16:50:46 +02:00
2022-09-30 15:09:52 +02:00
return width;
2022-09-29 16:50:46 +02:00
}
2022-09-26 17:51:28 +02:00
ShapeItem::ShapeItem( QQuickItem* parent )
: QskControl( parent )
{
setMargins( 20 );
setSizePolicy( QskSizePolicy::Ignored, QskSizePolicy::Ignored );
2022-09-26 17:51:28 +02:00
}
ShapeItem::~ShapeItem()
{
}
void ShapeItem::setPen( const QPen& pen )
{
if ( pen != m_pen )
{
m_pen = pen;
update();
}
}
QPen ShapeItem::pen() const
{
return m_pen;
}
2022-10-31 14:42:08 +01:00
void ShapeItem::setGradient( const QskGradient& gradient )
2022-09-26 17:51:28 +02:00
{
if ( gradient != m_gradient )
2022-09-26 17:51:28 +02:00
{
m_gradient = gradient;
2022-09-26 17:51:28 +02:00
update();
}
}
2022-10-31 14:42:08 +01:00
const QskGradient& ShapeItem::gradient() const
2022-09-29 16:50:46 +02:00
{
return m_gradient;
2022-09-29 16:50:46 +02:00
}
2022-09-26 17:51:28 +02:00
void ShapeItem::setPath( const QPainterPath& path )
{
if ( path != m_path )
{
m_path = path;
update();
}
}
QPainterPath ShapeItem::path() const
{
return m_path;
}
void ShapeItem::updateNode( QSGNode* parentNode )
{
enum NodeRole
{
2022-09-27 15:06:44 +02:00
FillRole,
BorderRole
2022-09-26 17:51:28 +02:00
};
const auto rect = contentsRect();
2022-09-29 16:50:46 +02:00
const auto pathRect = m_path.controlPointRect();
2022-09-26 17:51:28 +02:00
2022-10-31 14:42:08 +01:00
auto fillNode = static_cast< QskShapeNode* >(
2022-09-27 15:06:44 +02:00
QskSGNode::findChildNode( parentNode, FillRole ) );
2022-09-26 17:51:28 +02:00
2022-09-29 16:50:46 +02:00
auto borderNode = static_cast< QskStrokeNode* >(
QskSGNode::findChildNode( parentNode, BorderRole ) );
if ( rect.isEmpty() || pathRect.isEmpty() )
2022-09-26 17:51:28 +02:00
{
2022-09-27 15:06:44 +02:00
delete fillNode;
2022-09-29 16:50:46 +02:00
delete borderNode;
return;
2022-09-26 17:51:28 +02:00
}
2022-09-29 16:50:46 +02:00
if ( m_gradient.isVisible() )
2022-09-26 17:51:28 +02:00
{
2022-09-27 15:06:44 +02:00
if ( fillNode == nullptr )
2022-09-26 17:51:28 +02:00
{
2022-10-31 14:42:08 +01:00
fillNode = new QskShapeNode;
2022-09-27 15:06:44 +02:00
QskSGNode::setNodeRole( fillNode, FillRole );
2022-09-29 16:50:46 +02:00
parentNode->prependChildNode( fillNode );
2022-09-26 17:51:28 +02:00
}
2022-09-29 16:50:46 +02:00
auto fillRect = rect;
2022-09-30 15:09:52 +02:00
if ( m_pen.style() != Qt::NoPen )
2022-09-29 16:50:46 +02:00
{
2022-09-30 15:09:52 +02:00
const auto pw2 = 0.5 * ::effectivePenWidth( m_pen, rect, pathRect );
2022-09-29 16:50:46 +02:00
fillRect.adjust( pw2, pw2, -pw2, -pw2 );
}
const auto transform = ::transformForRects( pathRect, fillRect );
2022-10-31 14:42:08 +01:00
fillNode->updateNode( m_path, transform, fillRect, m_gradient );
2022-09-26 17:51:28 +02:00
}
2022-09-29 16:50:46 +02:00
else
2022-09-26 17:51:28 +02:00
{
2022-09-29 16:50:46 +02:00
delete fillNode;
2022-09-26 17:51:28 +02:00
}
2022-09-29 16:50:46 +02:00
2022-09-30 15:09:52 +02:00
if ( ::isVisible( m_pen ) )
2022-09-26 17:51:28 +02:00
{
2022-09-30 15:09:52 +02:00
#if 0
if ( m_pen.widthF() > 1.0 )
2022-09-29 16:50:46 +02:00
{
2022-09-30 15:09:52 +02:00
if ( !( m_pen.isSolid() && m_pen.color().alpha() == 255 ) )
2022-09-29 16:50:46 +02:00
{
/*
We might end up with overlapping parts
at corners with angles < 180°
What about translating the stroke into
a path ( QPainterPathStroker ) and using
a QskShapeNode then. TODO ...
*/
}
}
2022-09-30 15:09:52 +02:00
#endif
2022-09-29 16:50:46 +02:00
2022-09-27 15:06:44 +02:00
if ( borderNode == nullptr )
2022-09-26 17:51:28 +02:00
{
2022-09-27 15:06:44 +02:00
borderNode = new QskStrokeNode;
QskSGNode::setNodeRole( borderNode, BorderRole );
2022-09-26 17:51:28 +02:00
2022-09-27 15:06:44 +02:00
parentNode->appendChildNode( borderNode );
2022-09-29 16:50:46 +02:00
}
2022-09-27 15:06:44 +02:00
2022-09-29 16:50:46 +02:00
const auto transform = ::transformForRects( pathRect, rect );
2022-09-30 15:09:52 +02:00
borderNode->updateNode( m_path, transform, m_pen );
2022-09-29 16:50:46 +02:00
}
else
{
delete borderNode;
}
2022-09-27 15:06:44 +02:00
}
2022-09-26 17:51:28 +02:00
#include "moc_ShapeItem.cpp"