QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskStrokeNode.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskStrokeNode.h"
7#include "QskVertex.h"
8#include "QskGradient.h"
9#include "QskRgbValue.h"
10
11#include <qpainterpath.h>
12
13QSK_QT_PRIVATE_BEGIN
14#include <private/qtriangulatingstroker_p.h>
15QSK_QT_PRIVATE_END
16
17static inline bool qskIsPenVisible( const QPen& pen )
18{
19 if ( pen.style() == Qt::NoPen )
20 return false;
21
22 if ( pen.brush().gradient() )
23 {
24 // TODO ...
25 }
26 else
27 {
28 if ( !QskRgb::isVisible( pen.color() ) )
29 return false;
30 }
31
32 return true;
33}
34
35QskStrokeNode::QskStrokeNode()
36{
37}
38
39QskStrokeNode::~QskStrokeNode() = default;
40
41void QskStrokeNode::updatePath( const QPainterPath& path, const QPen& pen )
42{
43 updatePath( path, QTransform(), pen );
44}
45
46void QskStrokeNode::updatePath(
47 const QPainterPath& path, const QTransform& transform, const QPen& pen )
48{
49 if ( path.isEmpty() || !qskIsPenVisible( pen ) )
50 {
51 resetGeometry();
52 return;
53 }
54
55 if ( auto qGradient = pen.brush().gradient() )
56 {
57 const auto r = transform.mapRect( path.boundingRect() );
58
59 QskGradient gradient( *qGradient );
60 gradient.setStretchMode( QskGradient::StretchToSize );
61
62 setColoring( r, gradient );
63 }
64 else
65 setColoring( pen.color() );
66
67 if ( true ) // For the moment we always update the geometry. TODO ...
68 {
69 /*
70 Unfortunately QTriangulatingStroker does not offer on the fly
71 transformations - like with qTriangulate. TODO ...
72 */
73 const auto scaledPath = transform.map( path );
74
75 auto effectivePen = pen;
76
77 if ( !effectivePen.isCosmetic() )
78 {
79 const auto scaleFactor = qMin( transform.m11(), transform.m22() );
80 if ( scaleFactor != 1.0 )
81 {
82 effectivePen.setWidth( effectivePen.widthF() * scaleFactor );
83 effectivePen.setCosmetic( false );
84 }
85 }
86
87 QTriangulatingStroker stroker;
88
89 if ( pen.style() == Qt::SolidLine )
90 {
91 // clipRect, renderHint are ignored in QTriangulatingStroker::process
92 stroker.process( qtVectorPathForPath( scaledPath ), effectivePen, {}, {} );
93 }
94 else
95 {
96 constexpr QRectF clipRect; // empty rect: no clipping
97
98 QDashedStrokeProcessor dashStroker;
99 dashStroker.process( qtVectorPathForPath( scaledPath ),
100 effectivePen, clipRect, {} );
101
102 const QVectorPath dashedVectorPath( dashStroker.points(),
103 dashStroker.elementCount(), dashStroker.elementTypes(), 0 );
104
105 stroker.process( dashedVectorPath, effectivePen, {}, {} );
106 }
107
108 auto& geometry = *this->geometry();
109
110 // 2 vertices for each point
111 geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
112 geometry.allocate( stroker.vertexCount() / 2 );
113
114 if ( isGeometryColored() )
115 {
116 const QskVertex::Color c( pen.color() );
117
118 const auto v = stroker.vertices();
119 auto points = geometry.vertexDataAsColoredPoint2D();
120
121 for ( int i = 0; i < geometry.vertexCount(); i++ )
122 {
123 const auto j = 2 * i;
124 points[i].set( v[j], v[j + 1], c.r, c.g, c.b, c.a );
125 }
126 }
127 else
128 {
129 memcpy( geometry.vertexData(), stroker.vertices(),
130 stroker.vertexCount() * sizeof( float ) );
131 }
132
133 geometry.markVertexDataDirty();
134 markDirty( QSGNode::DirtyGeometry );
135 }
136}