Introduce hardware accelerated curve renderer for Shapes
This implements the Loop/Blinn algorithm for quadratic curves as an optional backend for Qt Quick Shapes, basically distance fields where the distance to curves are calculated in the fragment shader. This means cubic curves are approximated, which will give varying results, but for many shapes (such as text) this is efficient and means the shapes can be zoomed indefinitely while still retaining curvature as well as anti-aliasing working without MSAA. Preliminary results give some frame rate improvements compared to doing MSAA and GeometryRenderer, but the major improvement is that you can get smooth curves at any zoom level without re-triangulating the shape. Note that the renderer currently does not do antialiasing for straight lines. This would still require MSAA, but at a lower cost than for GeometryRenderer since there are much fewer triangles. Adding AA here as well is work in progress. Task-number: QTBUG-104122 Done-with: Paul Olav Tvete <paul.tvete@qt.io> Done-with: Eirik Aavitsland <eirik.aavitsland@qt.io> Done-with: Amr Elsayed <amr.elsayed@qt.io> Change-Id: I6b4a1103546fbdfe760906f7a183101f8eedb9d3 Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io> Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
parent
f6e5a11f0c
commit
be813b9955
|
@ -56,7 +56,7 @@ Rectangle {
|
||||||
property Component shapeType: Component {
|
property Component shapeType: Component {
|
||||||
ShapePath {
|
ShapePath {
|
||||||
id: quadShapePath
|
id: quadShapePath
|
||||||
strokeColor: root.palette.windowText
|
strokeColor: strokeSwitch.checked ? root.palette.windowText : "transparent"
|
||||||
strokeWidth: widthSlider.value
|
strokeWidth: widthSlider.value
|
||||||
fillColor: fillSwitch.checked ? "green" : "transparent"
|
fillColor: fillSwitch.checked ? "green" : "transparent"
|
||||||
PathQuad {
|
PathQuad {
|
||||||
|
@ -83,7 +83,7 @@ Rectangle {
|
||||||
property Component shapeType: Component {
|
property Component shapeType: Component {
|
||||||
ShapePath {
|
ShapePath {
|
||||||
id: cubicShapePath
|
id: cubicShapePath
|
||||||
strokeColor: root.palette.windowText
|
strokeColor: strokeSwitch.checked ? root.palette.windowText : "transparent"
|
||||||
strokeWidth: widthSlider.value
|
strokeWidth: widthSlider.value
|
||||||
fillColor: fillSwitch.checked ? "green" : "transparent"
|
fillColor: fillSwitch.checked ? "green" : "transparent"
|
||||||
PathCubic {
|
PathCubic {
|
||||||
|
@ -109,6 +109,15 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ToolButton {
|
||||||
|
id: modifyButton
|
||||||
|
text: qsTr("Modify")
|
||||||
|
checkable: true
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (checked)
|
||||||
|
showHandlesSwitch.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
@ -130,6 +139,12 @@ Rectangle {
|
||||||
id: fillSwitch
|
id: fillSwitch
|
||||||
text: qsTr("Fill")
|
text: qsTr("Fill")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Switch {
|
||||||
|
id: strokeSwitch
|
||||||
|
text: qsTr("Stroke")
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
|
@ -144,9 +159,11 @@ Rectangle {
|
||||||
|
|
||||||
width: 20
|
width: 20
|
||||||
height: width
|
height: width
|
||||||
|
radius: halfWidth
|
||||||
visible: showHandlesSwitch.checked
|
visible: showHandlesSwitch.checked
|
||||||
color: hh.hovered ? "yellow" : idleColor
|
color: hh.hovered ? "yellow" : idleColor
|
||||||
border.color: "grey"
|
border.color: "grey"
|
||||||
|
opacity: 0.75
|
||||||
|
|
||||||
property real halfWidth: width / 2
|
property real halfWidth: width / 2
|
||||||
property bool complete: false
|
property bool complete: false
|
||||||
|
@ -203,14 +220,16 @@ Rectangle {
|
||||||
property ShapePath activePath: null
|
property ShapePath activePath: null
|
||||||
onActiveChanged: {
|
onActiveChanged: {
|
||||||
const tool = toolButtons.checkedButton;
|
const tool = toolButtons.checkedButton;
|
||||||
if (active) {
|
if (tool != modifyButton) {
|
||||||
activePath = tool.shapeType.createObject(root, {
|
if (active) {
|
||||||
startX: centroid.position.x, startY: centroid.position.y
|
activePath = tool.shapeType.createObject(root, {
|
||||||
});
|
startX: centroid.position.x, startY: centroid.position.y
|
||||||
shape.data.push(activePath);
|
});
|
||||||
} else {
|
shape.data.push(activePath);
|
||||||
activePath.finishCreation();
|
} else {
|
||||||
activePath = null;
|
activePath.finishCreation();
|
||||||
|
activePath = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onCentroidChanged: if (activePath) {
|
onCentroidChanged: if (activePath) {
|
||||||
|
|
|
@ -159,8 +159,8 @@ Rectangle {
|
||||||
}
|
}
|
||||||
color: "darkBlue"
|
color: "darkBlue"
|
||||||
font.pointSize: 12
|
font.pointSize: 12
|
||||||
readonly property variant rendererStrings: [ qsTr("Unknown"), qsTr("Generic (QtGui triangulator)"), qsTr("GL_NV_path_rendering"), qsTr("Software (QPainter)") ]
|
readonly property variant rendererStrings: [ qsTr("Unknown"), qsTr("Generic (QtGui triangulator)"), qsTr("GL_NV_path_rendering"), qsTr("Software (QPainter)"), qsTr("Curve Renderer") ]
|
||||||
text: qsTr("Active Shape backend: ") + rendererStrings[dummyShape.rendererType]
|
text: "Active Shape backend: " + rendererStrings[dummyShape.rendererType]
|
||||||
SequentialAnimation on opacity {
|
SequentialAnimation on opacity {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
from: 1
|
from: 1
|
||||||
|
|
|
@ -372,6 +372,9 @@ void QQuickPath::processPath()
|
||||||
d->_path = createPath(QPointF(), QPointF(), d->_attributes, d->pathLength, d->_attributePoints, &d->closed);
|
d->_path = createPath(QPointF(), QPointF(), d->_attributes, d->pathLength, d->_attributePoints, &d->closed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (d->simplified)
|
||||||
|
d->_path = d->_path.simplified();
|
||||||
|
|
||||||
emit changed();
|
emit changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,6 +715,32 @@ void QQuickPath::invalidateSequentialHistory() const
|
||||||
d->prevBez.isValid = false;
|
d->prevBez.isValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \qmlproperty bool QtQuick::Path::simplified
|
||||||
|
\since 6.6
|
||||||
|
|
||||||
|
When set to true, the path will be simplified. This implies merging all subpaths that intersect,
|
||||||
|
creating a path where there are no self-intersections. Consecutive parallel lines will also be
|
||||||
|
merged. The simplified path is intended to be used with ShapePath.OddEvenFill. Bezier curves may
|
||||||
|
be flattened to line segments due to numerical instability of doing bezier curve intersections.
|
||||||
|
*/
|
||||||
|
void QQuickPath::setSimplified(bool simplified)
|
||||||
|
{
|
||||||
|
Q_D(QQuickPath);
|
||||||
|
if (d->simplified == simplified)
|
||||||
|
return;
|
||||||
|
|
||||||
|
d->simplified = simplified;
|
||||||
|
processPath();
|
||||||
|
|
||||||
|
emit simplifiedChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QQuickPath::simplified() const
|
||||||
|
{
|
||||||
|
Q_D(const QQuickPath);
|
||||||
|
return d->simplified;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty size QtQuick::Path::scale
|
\qmlproperty size QtQuick::Path::scale
|
||||||
|
|
||||||
|
|
|
@ -487,6 +487,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPath : public QObject, public QQmlParserStatu
|
||||||
Q_PROPERTY(qreal startX READ startX WRITE setStartX NOTIFY startXChanged)
|
Q_PROPERTY(qreal startX READ startX WRITE setStartX NOTIFY startXChanged)
|
||||||
Q_PROPERTY(qreal startY READ startY WRITE setStartY NOTIFY startYChanged)
|
Q_PROPERTY(qreal startY READ startY WRITE setStartY NOTIFY startYChanged)
|
||||||
Q_PROPERTY(bool closed READ isClosed NOTIFY changed)
|
Q_PROPERTY(bool closed READ isClosed NOTIFY changed)
|
||||||
|
Q_PROPERTY(bool simplified READ simplified WRITE setSimplified NOTIFY simplifiedChanged REVISION(6, 6))
|
||||||
Q_PROPERTY(QSizeF scale READ scale WRITE setScale NOTIFY scaleChanged REVISION(2, 14))
|
Q_PROPERTY(QSizeF scale READ scale WRITE setScale NOTIFY scaleChanged REVISION(2, 14))
|
||||||
Q_CLASSINFO("DefaultProperty", "pathElements")
|
Q_CLASSINFO("DefaultProperty", "pathElements")
|
||||||
QML_NAMED_ELEMENT(Path)
|
QML_NAMED_ELEMENT(Path)
|
||||||
|
@ -517,10 +518,14 @@ public:
|
||||||
QSizeF scale() const;
|
QSizeF scale() const;
|
||||||
void setScale(const QSizeF &scale);
|
void setScale(const QSizeF &scale);
|
||||||
|
|
||||||
|
bool simplified() const;
|
||||||
|
void setSimplified(bool simplified);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void changed();
|
void changed();
|
||||||
void startXChanged();
|
void startXChanged();
|
||||||
void startYChanged();
|
void startYChanged();
|
||||||
|
Q_REVISION(6, 6) void simplifiedChanged();
|
||||||
Q_REVISION(2, 14) void scaleChanged();
|
Q_REVISION(2, 14) void scaleChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -53,6 +53,7 @@ public:
|
||||||
bool closed = false;
|
bool closed = false;
|
||||||
bool componentComplete = true;
|
bool componentComplete = true;
|
||||||
bool isShapePath = false;
|
bool isShapePath = false;
|
||||||
|
bool simplified = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
|
@ -20,12 +20,16 @@ qt_internal_add_qml_module(QuickShapesPrivate
|
||||||
qquickshape_p_p.h
|
qquickshape_p_p.h
|
||||||
qquickshapegenericrenderer.cpp qquickshapegenericrenderer_p.h
|
qquickshapegenericrenderer.cpp qquickshapegenericrenderer_p.h
|
||||||
qquickshapesglobal.h qquickshapesglobal_p.h
|
qquickshapesglobal.h qquickshapesglobal_p.h
|
||||||
|
qquickshapecurverenderer.cpp qquickshapecurverenderer_p.h qquickshapecurverenderer_p_p.h
|
||||||
|
qt_delaunay_triangulator.cpp
|
||||||
|
qt_quadratic_bezier.cpp
|
||||||
qquickshapesoftwarerenderer.cpp qquickshapesoftwarerenderer_p.h
|
qquickshapesoftwarerenderer.cpp qquickshapesoftwarerenderer_p.h
|
||||||
PUBLIC_LIBRARIES
|
PUBLIC_LIBRARIES
|
||||||
Qt::Core
|
Qt::Core
|
||||||
Qt::GuiPrivate
|
Qt::GuiPrivate
|
||||||
Qt::Qml
|
Qt::Qml
|
||||||
Qt::QuickPrivate
|
Qt::QuickPrivate
|
||||||
|
Qt::ShaderTools
|
||||||
GENERATE_CPP_EXPORTS
|
GENERATE_CPP_EXPORTS
|
||||||
GENERATE_PRIVATE_CPP_EXPORTS
|
GENERATE_PRIVATE_CPP_EXPORTS
|
||||||
)
|
)
|
||||||
|
@ -51,4 +55,120 @@ qt_internal_add_shaders(QuickShapesPrivate "qtquickshapes_shaders"
|
||||||
"shaders_ng/radialgradient.frag"
|
"shaders_ng/radialgradient.frag"
|
||||||
"shaders_ng/conicalgradient.vert"
|
"shaders_ng/conicalgradient.vert"
|
||||||
"shaders_ng/conicalgradient.frag"
|
"shaders_ng/conicalgradient.frag"
|
||||||
|
"shaders_ng/shapecurve.frag"
|
||||||
|
"shaders_ng/shapecurve.vert"
|
||||||
|
"shaders_ng/wireframe.frag"
|
||||||
|
"shaders_ng/wireframe.vert"
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_internal_add_shaders(QuickShapesPrivate "shaders_stroke"
|
||||||
|
BATCHABLE
|
||||||
|
PRECOMPILE
|
||||||
|
OPTIMIZED
|
||||||
|
DEFINES "STROKE"
|
||||||
|
PREFIX
|
||||||
|
"/qt-project.org/shapes"
|
||||||
|
FILES
|
||||||
|
"shaders_ng/shapecurve.frag"
|
||||||
|
"shaders_ng/shapecurve.vert"
|
||||||
|
OUTPUTS
|
||||||
|
"shaders_ng/shapecurve_stroke.frag.qsb"
|
||||||
|
"shaders_ng/shapecurve_stroke.vert.qsb"
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_internal_add_shaders(QuickShapesPrivate "shaders_lg"
|
||||||
|
BATCHABLE
|
||||||
|
PRECOMPILE
|
||||||
|
OPTIMIZED
|
||||||
|
DEFINES "LINEARGRADIENT"
|
||||||
|
PREFIX
|
||||||
|
"/qt-project.org/shapes"
|
||||||
|
FILES
|
||||||
|
"shaders_ng/shapecurve.frag"
|
||||||
|
"shaders_ng/shapecurve.vert"
|
||||||
|
OUTPUTS
|
||||||
|
"shaders_ng/shapecurve_lg.frag.qsb"
|
||||||
|
"shaders_ng/shapecurve_lg.vert.qsb"
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_internal_add_shaders(QuickShapesPrivate "shaders_lg_stroke"
|
||||||
|
BATCHABLE
|
||||||
|
PRECOMPILE
|
||||||
|
OPTIMIZED
|
||||||
|
DEFINES
|
||||||
|
"LINEARGRADIENT"
|
||||||
|
"STROKE"
|
||||||
|
PREFIX
|
||||||
|
"/qt-project.org/shapes"
|
||||||
|
FILES
|
||||||
|
"shaders_ng/shapecurve.frag"
|
||||||
|
"shaders_ng/shapecurve.vert"
|
||||||
|
OUTPUTS
|
||||||
|
"shaders_ng/shapecurve_lg_stroke.frag.qsb"
|
||||||
|
"shaders_ng/shapecurve_lg_stroke.vert.qsb"
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_internal_add_shaders(QuickShapesPrivate "shaders_rg"
|
||||||
|
BATCHABLE
|
||||||
|
PRECOMPILE
|
||||||
|
OPTIMIZED
|
||||||
|
DEFINES "RADIALGRADIENT"
|
||||||
|
PREFIX
|
||||||
|
"/qt-project.org/shapes"
|
||||||
|
FILES
|
||||||
|
"shaders_ng/shapecurve.frag"
|
||||||
|
"shaders_ng/shapecurve.vert"
|
||||||
|
OUTPUTS
|
||||||
|
"shaders_ng/shapecurve_rg.frag.qsb"
|
||||||
|
"shaders_ng/shapecurve_rg.vert.qsb"
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_internal_add_shaders(QuickShapesPrivate "shaders_rg_stroke"
|
||||||
|
BATCHABLE
|
||||||
|
PRECOMPILE
|
||||||
|
OPTIMIZED
|
||||||
|
DEFINES
|
||||||
|
"RADIALGRADIENT"
|
||||||
|
"STROKE"
|
||||||
|
PREFIX
|
||||||
|
"/qt-project.org/shapes"
|
||||||
|
FILES
|
||||||
|
"shaders_ng/shapecurve.frag"
|
||||||
|
"shaders_ng/shapecurve.vert"
|
||||||
|
OUTPUTS
|
||||||
|
"shaders_ng/shapecurve_rg_stroke.frag.qsb"
|
||||||
|
"shaders_ng/shapecurve_rg_stroke.vert.qsb"
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_internal_add_shaders(QuickShapesPrivate "shaders_cg"
|
||||||
|
BATCHABLE
|
||||||
|
PRECOMPILE
|
||||||
|
OPTIMIZED
|
||||||
|
DEFINES
|
||||||
|
"CONICALGRADIENT"
|
||||||
|
PREFIX
|
||||||
|
"/qt-project.org/shapes"
|
||||||
|
FILES
|
||||||
|
"shaders_ng/shapecurve.frag"
|
||||||
|
"shaders_ng/shapecurve.vert"
|
||||||
|
OUTPUTS
|
||||||
|
"shaders_ng/shapecurve_cg.frag.qsb"
|
||||||
|
"shaders_ng/shapecurve_cg.vert.qsb"
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_internal_add_shaders(QuickShapesPrivate "shaders_cg_stroke"
|
||||||
|
BATCHABLE
|
||||||
|
PRECOMPILE
|
||||||
|
OPTIMIZED
|
||||||
|
DEFINES
|
||||||
|
"CONICALGRADIENT"
|
||||||
|
"STROKE"
|
||||||
|
PREFIX
|
||||||
|
"/qt-project.org/shapes"
|
||||||
|
FILES
|
||||||
|
"shaders_ng/shapecurve.frag"
|
||||||
|
"shaders_ng/shapecurve.vert"
|
||||||
|
OUTPUTS
|
||||||
|
"shaders_ng/shapecurve_cg_stroke.frag.qsb"
|
||||||
|
"shaders_ng/shapecurve_cg_stroke.vert.qsb"
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "qquickshape_p_p.h"
|
#include "qquickshape_p_p.h"
|
||||||
#include "qquickshapegenericrenderer_p.h"
|
#include "qquickshapegenericrenderer_p.h"
|
||||||
#include "qquickshapesoftwarerenderer_p.h"
|
#include "qquickshapesoftwarerenderer_p.h"
|
||||||
|
#include "qquickshapecurverenderer_p.h"
|
||||||
#include <private/qsgplaintexture_p.h>
|
#include <private/qsgplaintexture_p.h>
|
||||||
#include <private/qquicksvgparser_p.h>
|
#include <private/qquicksvgparser_p.h>
|
||||||
#include <QtGui/private/qdrawhelper_p.h>
|
#include <QtGui/private/qdrawhelper_p.h>
|
||||||
|
@ -639,6 +640,7 @@ void QQuickShapePrivate::_q_shapePathChanged()
|
||||||
Q_Q(QQuickShape);
|
Q_Q(QQuickShape);
|
||||||
spChanged = true;
|
spChanged = true;
|
||||||
q->polish();
|
q->polish();
|
||||||
|
emit q->boundingRectChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQuickShapePrivate::setStatus(QQuickShape::Status newStatus)
|
void QQuickShapePrivate::setStatus(QQuickShape::Status newStatus)
|
||||||
|
@ -678,6 +680,45 @@ QQuickShape::~QQuickShape()
|
||||||
Pure QPainter drawing using the raster paint engine. This is the
|
Pure QPainter drawing using the raster paint engine. This is the
|
||||||
default, and only, option when the Qt Quick scenegraph is running
|
default, and only, option when the Qt Quick scenegraph is running
|
||||||
with the \c software backend.
|
with the \c software backend.
|
||||||
|
|
||||||
|
\value Shape.CurveRenderer
|
||||||
|
Added as technology preview in Qt 6.6.
|
||||||
|
Experimental renderer which triangulates the polygonal internal hull of the shape,
|
||||||
|
similar to \c Shape.GeometryRenderer. But instead of also triangulating curved areas,
|
||||||
|
this renderer renders curved areas using a specialized fragment shader. This means that
|
||||||
|
the shape does not need to be re-tesselated when it changes size or is zoomed. For
|
||||||
|
supported shapes, this can give improved runtime performance in cases where the shapes
|
||||||
|
are repeatedly transformed.
|
||||||
|
|
||||||
|
By default, \c Shape.GeometryRenderer will be selected unless the Qt Quick scenegraph is running
|
||||||
|
with the \c software backend. In that case, \c Shape.SoftwareRenderer will be used.
|
||||||
|
|
||||||
|
\c Shape.CurveRenderer can be optionally selected using the \l preferredRendererType property.
|
||||||
|
|
||||||
|
In addition to rendering smooth curves regardless of zoom level, this renderer applies
|
||||||
|
anti-aliasing without enabling MSAA on the surface, which may provide performance gain.
|
||||||
|
|
||||||
|
Note that \c Shape.CurveRenderer is currently regarded as experimental and has several
|
||||||
|
limitations:
|
||||||
|
\list 1
|
||||||
|
\li The \c GL_OES_standard_derivatives extension to OpenGL is required when the OpenGL
|
||||||
|
RHI backend is in use (this is available by default on OpenGL ES 3 and later, but
|
||||||
|
optional in OpenGL ES 2).
|
||||||
|
\li Only quadratic curves are supported (cubic curves will be approximated by quadratic
|
||||||
|
curves).
|
||||||
|
\li Shapes where elements intersect are not supported. Use the \l Path.simplified
|
||||||
|
property to remove self-intersections from such shapes.
|
||||||
|
\li Shapes that span a large numerical range, such as a long string of text, may have
|
||||||
|
issues. Consider splitting these shapes into multiple ones, for instance by making
|
||||||
|
a \l PathText for each individual word.
|
||||||
|
|
||||||
|
Due to the fact that the \c Shape.CurveRenderer approximates cubic curves, there are certain
|
||||||
|
shapes it will not render accurately. For instance, circular arcs are not representable using quadratic
|
||||||
|
curves and will only look approximately correct. If the visual representation is
|
||||||
|
insufficient for a particular shape, consider using \c Shape.GeometryRenderer instead.
|
||||||
|
|
||||||
|
\note The \c Shape.CurveRenderer is currently considered a tech preview, thus the name of
|
||||||
|
this enum may change in future versions of Qt and some shapes may render incorrectly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QQuickShape::RendererType QQuickShape::rendererType() const
|
QQuickShape::RendererType QQuickShape::rendererType() const
|
||||||
|
@ -686,6 +727,56 @@ QQuickShape::RendererType QQuickShape::rendererType() const
|
||||||
return d->rendererType;
|
return d->rendererType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty enumeration QtQuick.Shapes::Shape::preferredRendererType
|
||||||
|
\since 6.6
|
||||||
|
|
||||||
|
Requests a specific backend to use for rendering the shape. The possible values are the same as
|
||||||
|
for \l rendererType. The default is Shape.UnknownRenderer, indicating no particular preference.
|
||||||
|
|
||||||
|
If the requested renderer type is not supported for the current Qt Quick backend, the default
|
||||||
|
renderer for that backend will be used instead. This will be reflected in the \l rendererType
|
||||||
|
when the backend is initialized.
|
||||||
|
|
||||||
|
\l Shape.SoftwareRenderer can currently not be selected without running the scenegraph with
|
||||||
|
the \c software backend, in which case it will be selected regardless of the
|
||||||
|
\c preferredRendererType.
|
||||||
|
|
||||||
|
\note This API is considered tech preview and may change or be removed in future versions of
|
||||||
|
Qt.
|
||||||
|
|
||||||
|
See \l rendererType for more information on the implications.
|
||||||
|
*/
|
||||||
|
|
||||||
|
QQuickShape::RendererType QQuickShape::preferredRendererType() const
|
||||||
|
{
|
||||||
|
Q_D(const QQuickShape);
|
||||||
|
return d->preferredType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QQuickShape::setPreferredRendererType(QQuickShape::RendererType preferredType)
|
||||||
|
{
|
||||||
|
Q_D(QQuickShape);
|
||||||
|
if (d->preferredType == preferredType)
|
||||||
|
return;
|
||||||
|
|
||||||
|
d->preferredType = preferredType;
|
||||||
|
// (could bail out here if selectRenderType shows no change?)
|
||||||
|
|
||||||
|
for (int i = 0; i < d->sp.size(); ++i) {
|
||||||
|
QQuickShapePath *p = d->sp[i];
|
||||||
|
QQuickShapePathPrivate *pp = QQuickShapePathPrivate::get(p);
|
||||||
|
pp->dirty |= QQuickShapePathPrivate::DirtyAll;
|
||||||
|
}
|
||||||
|
d->spChanged = true;
|
||||||
|
d->_q_shapePathChanged();
|
||||||
|
polish();
|
||||||
|
update();
|
||||||
|
|
||||||
|
emit preferredRendererTypeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty bool QtQuick.Shapes::Shape::asynchronous
|
\qmlproperty bool QtQuick.Shapes::Shape::asynchronous
|
||||||
|
|
||||||
|
@ -719,6 +810,23 @@ void QQuickShape::setAsynchronous(bool async)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty rect QtQuick.Shapes::Shape::boundingRect
|
||||||
|
\since 6.6
|
||||||
|
|
||||||
|
Contains the united bounding rect of all sub paths in the shape.
|
||||||
|
*/
|
||||||
|
QRectF QQuickShape::boundingRect() const
|
||||||
|
{
|
||||||
|
Q_D(const QQuickShape);
|
||||||
|
QRectF brect;
|
||||||
|
for (QQuickShapePath *path : d->sp) {
|
||||||
|
brect = brect.united(path->path().boundingRect());
|
||||||
|
}
|
||||||
|
|
||||||
|
return brect;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty bool QtQuick.Shapes::Shape::vendorExtensionsEnabled
|
\qmlproperty bool QtQuick.Shapes::Shape::vendorExtensionsEnabled
|
||||||
|
|
||||||
|
@ -902,6 +1010,12 @@ void QQuickShape::updatePolish()
|
||||||
d->spChanged = false;
|
d->spChanged = false;
|
||||||
d->effectRefCount = currentEffectRefCount;
|
d->effectRefCount = currentEffectRefCount;
|
||||||
|
|
||||||
|
QQuickShape::RendererType expectedRenderer = d->selectRendererType();
|
||||||
|
if (d->rendererType != expectedRenderer) {
|
||||||
|
delete d->renderer;
|
||||||
|
d->renderer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!d->renderer) {
|
if (!d->renderer) {
|
||||||
d->createRenderer();
|
d->createRenderer();
|
||||||
if (!d->renderer)
|
if (!d->renderer)
|
||||||
|
@ -936,36 +1050,73 @@ QSGNode *QQuickShape::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
|
||||||
{
|
{
|
||||||
// Called on the render thread, with the gui thread blocked. We can now
|
// Called on the render thread, with the gui thread blocked. We can now
|
||||||
// safely access gui thread data.
|
// safely access gui thread data.
|
||||||
|
|
||||||
Q_D(QQuickShape);
|
Q_D(QQuickShape);
|
||||||
if (d->renderer) {
|
|
||||||
if (!node)
|
if (d->renderer || d->rendererChanged) {
|
||||||
|
if (!node || d->rendererChanged) {
|
||||||
|
d->rendererChanged = false;
|
||||||
|
delete node;
|
||||||
node = d->createNode();
|
node = d->createNode();
|
||||||
|
}
|
||||||
d->renderer->updateNode();
|
d->renderer->updateNode();
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QQuickShape::RendererType QQuickShapePrivate::selectRendererType()
|
||||||
|
{
|
||||||
|
QQuickShape::RendererType res = QQuickShape::UnknownRenderer;
|
||||||
|
Q_Q(QQuickShape);
|
||||||
|
QSGRendererInterface *ri = q->window()->rendererInterface();
|
||||||
|
if (!ri)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
static const bool environmentPreferCurve =
|
||||||
|
qEnvironmentVariable("QT_QUICKSHAPES_BACKEND").toLower() == QLatin1String("curve");
|
||||||
|
|
||||||
|
switch (ri->graphicsApi()) {
|
||||||
|
case QSGRendererInterface::Software:
|
||||||
|
res = QQuickShape::SoftwareRenderer;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (QSGRendererInterface::isApiRhiBased(ri->graphicsApi())) {
|
||||||
|
if (preferredType == QQuickShape::CurveRenderer || environmentPreferCurve) {
|
||||||
|
res = QQuickShape::CurveRenderer;
|
||||||
|
} else {
|
||||||
|
res = QQuickShape::GeometryRenderer;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qWarning("No path backend for this graphics API yet");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
// the renderer object lives on the gui thread
|
// the renderer object lives on the gui thread
|
||||||
void QQuickShapePrivate::createRenderer()
|
void QQuickShapePrivate::createRenderer()
|
||||||
{
|
{
|
||||||
Q_Q(QQuickShape);
|
Q_Q(QQuickShape);
|
||||||
QSGRendererInterface *ri = q->window()->rendererInterface();
|
QQuickShape::RendererType selectedType = selectRendererType();
|
||||||
if (!ri)
|
if (selectedType == QQuickShape::UnknownRenderer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (ri->graphicsApi()) {
|
rendererType = selectedType;
|
||||||
case QSGRendererInterface::Software:
|
rendererChanged = true;
|
||||||
rendererType = QQuickShape::SoftwareRenderer;
|
|
||||||
|
switch (selectedType) {
|
||||||
|
case QQuickShape::SoftwareRenderer:
|
||||||
renderer = new QQuickShapeSoftwareRenderer;
|
renderer = new QQuickShapeSoftwareRenderer;
|
||||||
break;
|
break;
|
||||||
|
case QQuickShape::GeometryRenderer:
|
||||||
|
renderer = new QQuickShapeGenericRenderer(q);
|
||||||
|
break;
|
||||||
|
case QQuickShape::CurveRenderer:
|
||||||
|
renderer = new QQuickShapeCurveRenderer(q);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (QSGRendererInterface::isApiRhiBased(ri->graphicsApi())) {
|
Q_UNREACHABLE();
|
||||||
rendererType = QQuickShape::GeometryRenderer;
|
|
||||||
renderer = new QQuickShapeGenericRenderer(q);
|
|
||||||
} else {
|
|
||||||
qWarning("No path backend for this graphics API yet");
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -989,9 +1140,15 @@ QSGNode *QQuickShapePrivate::createNode()
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (QSGRendererInterface::isApiRhiBased(ri->graphicsApi())) {
|
if (QSGRendererInterface::isApiRhiBased(ri->graphicsApi())) {
|
||||||
node = new QQuickShapeGenericNode;
|
if (rendererType == QQuickShape::CurveRenderer) {
|
||||||
static_cast<QQuickShapeGenericRenderer *>(renderer)->setRootNode(
|
node = new QQuickShapeCurveNode;
|
||||||
static_cast<QQuickShapeGenericNode *>(node));
|
static_cast<QQuickShapeCurveRenderer *>(renderer)->setRootNode(
|
||||||
|
static_cast<QQuickShapeCurveNode *>(node));
|
||||||
|
} else {
|
||||||
|
node = new QQuickShapeGenericNode;
|
||||||
|
static_cast<QQuickShapeGenericRenderer *>(renderer)->setRootNode(
|
||||||
|
static_cast<QQuickShapeGenericNode *>(node));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
qWarning("No path backend for this graphics API yet");
|
qWarning("No path backend for this graphics API yet");
|
||||||
}
|
}
|
||||||
|
|
|
@ -288,8 +288,12 @@ class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShape : public QQuickItem
|
||||||
Q_PROPERTY(RendererType rendererType READ rendererType NOTIFY rendererChanged)
|
Q_PROPERTY(RendererType rendererType READ rendererType NOTIFY rendererChanged)
|
||||||
Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged)
|
Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged)
|
||||||
Q_PROPERTY(bool vendorExtensionsEnabled READ vendorExtensionsEnabled WRITE setVendorExtensionsEnabled NOTIFY vendorExtensionsEnabledChanged)
|
Q_PROPERTY(bool vendorExtensionsEnabled READ vendorExtensionsEnabled WRITE setVendorExtensionsEnabled NOTIFY vendorExtensionsEnabledChanged)
|
||||||
|
Q_PROPERTY(RendererType preferredRendererType READ preferredRendererType
|
||||||
|
WRITE setPreferredRendererType NOTIFY preferredRendererTypeChanged REVISION(6, 6))
|
||||||
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
|
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
|
||||||
Q_PROPERTY(ContainsMode containsMode READ containsMode WRITE setContainsMode NOTIFY containsModeChanged REVISION(1, 11))
|
Q_PROPERTY(ContainsMode containsMode READ containsMode WRITE setContainsMode NOTIFY containsModeChanged REVISION(1, 11))
|
||||||
|
Q_PROPERTY(QRectF boundingRect READ boundingRect NOTIFY boundingRectChanged REVISION(6, 6))
|
||||||
|
|
||||||
Q_PROPERTY(QQmlListProperty<QObject> data READ data)
|
Q_PROPERTY(QQmlListProperty<QObject> data READ data)
|
||||||
Q_CLASSINFO("DefaultProperty", "data")
|
Q_CLASSINFO("DefaultProperty", "data")
|
||||||
QML_NAMED_ELEMENT(Shape)
|
QML_NAMED_ELEMENT(Shape)
|
||||||
|
@ -300,7 +304,8 @@ public:
|
||||||
UnknownRenderer,
|
UnknownRenderer,
|
||||||
GeometryRenderer,
|
GeometryRenderer,
|
||||||
NvprRenderer,
|
NvprRenderer,
|
||||||
SoftwareRenderer
|
SoftwareRenderer,
|
||||||
|
CurveRenderer
|
||||||
};
|
};
|
||||||
Q_ENUM(RendererType)
|
Q_ENUM(RendererType)
|
||||||
|
|
||||||
|
@ -325,6 +330,11 @@ public:
|
||||||
bool asynchronous() const;
|
bool asynchronous() const;
|
||||||
void setAsynchronous(bool async);
|
void setAsynchronous(bool async);
|
||||||
|
|
||||||
|
Q_REVISION(6, 6) RendererType preferredRendererType() const;
|
||||||
|
Q_REVISION(6, 6) void setPreferredRendererType(RendererType preferredType);
|
||||||
|
|
||||||
|
Q_REVISION(6, 6) QRectF boundingRect() const override;
|
||||||
|
|
||||||
bool vendorExtensionsEnabled() const;
|
bool vendorExtensionsEnabled() const;
|
||||||
void setVendorExtensionsEnabled(bool enable);
|
void setVendorExtensionsEnabled(bool enable);
|
||||||
|
|
||||||
|
@ -349,6 +359,8 @@ Q_SIGNALS:
|
||||||
void asynchronousChanged();
|
void asynchronousChanged();
|
||||||
void vendorExtensionsEnabledChanged();
|
void vendorExtensionsEnabledChanged();
|
||||||
void statusChanged();
|
void statusChanged();
|
||||||
|
Q_REVISION(6, 6) void preferredRendererTypeChanged();
|
||||||
|
Q_REVISION(6, 6) void boundingRectChanged();
|
||||||
Q_REVISION(1, 11) void containsModeChanged();
|
Q_REVISION(1, 11) void containsModeChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -41,7 +41,7 @@ public:
|
||||||
enum FillGradientType { NoGradient = 0, LinearGradient, RadialGradient, ConicalGradient };
|
enum FillGradientType { NoGradient = 0, LinearGradient, RadialGradient, ConicalGradient };
|
||||||
struct GradientDesc { // can fully describe a linear/radial/conical gradient
|
struct GradientDesc { // can fully describe a linear/radial/conical gradient
|
||||||
QGradientStops stops;
|
QGradientStops stops;
|
||||||
QQuickShapeGradient::SpreadMode spread;
|
QQuickShapeGradient::SpreadMode spread = QQuickShapeGradient::PadSpread;
|
||||||
QPointF a; // start (L) or center point (R/C)
|
QPointF a; // start (L) or center point (R/C)
|
||||||
QPointF b; // end (L) or focal point (R)
|
QPointF b; // end (L) or focal point (R)
|
||||||
qreal v0; // center radius (R) or start angle (C)
|
qreal v0; // center radius (R) or start angle (C)
|
||||||
|
@ -127,6 +127,7 @@ public:
|
||||||
QQuickShapePrivate();
|
QQuickShapePrivate();
|
||||||
~QQuickShapePrivate();
|
~QQuickShapePrivate();
|
||||||
|
|
||||||
|
QQuickShape::RendererType selectRendererType();
|
||||||
void createRenderer();
|
void createRenderer();
|
||||||
QSGNode *createNode();
|
QSGNode *createNode();
|
||||||
void sync();
|
void sync();
|
||||||
|
@ -146,8 +147,10 @@ public:
|
||||||
int syncTimeCounter = 0;
|
int syncTimeCounter = 0;
|
||||||
QQuickShape::Status status = QQuickShape::Null;
|
QQuickShape::Status status = QQuickShape::Null;
|
||||||
QQuickShape::RendererType rendererType = QQuickShape::UnknownRenderer;
|
QQuickShape::RendererType rendererType = QQuickShape::UnknownRenderer;
|
||||||
|
QQuickShape::RendererType preferredType = QQuickShape::UnknownRenderer;
|
||||||
QQuickShape::ContainsMode containsMode = QQuickShape::BoundingRectContains;
|
QQuickShape::ContainsMode containsMode = QQuickShape::BoundingRectContains;
|
||||||
bool spChanged = false;
|
bool spChanged = false;
|
||||||
|
bool rendererChanged = false;
|
||||||
bool async = false;
|
bool async = false;
|
||||||
bool enableVendorExts = false;
|
bool enableVendorExts = false;
|
||||||
bool syncTimingActive = false;
|
bool syncTimingActive = false;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,345 @@
|
||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||||
|
|
||||||
|
#ifndef QQUICKSHAPECURVERENDERER_P_H
|
||||||
|
#define QQUICKSHAPECURVERENDERER_P_H
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G
|
||||||
|
// -------------
|
||||||
|
//
|
||||||
|
// This file is not part of the Qt API. It exists for the convenience
|
||||||
|
// of a number of Qt sources files. This header file may change from
|
||||||
|
// version to version without notice, or even be removed.
|
||||||
|
//
|
||||||
|
// We mean it.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QtQuickShapes/private/qquickshapesglobal_p.h>
|
||||||
|
#include <QtQuickShapes/private/qquickshape_p_p.h>
|
||||||
|
#include <qsgnode.h>
|
||||||
|
#include <qsggeometry.h>
|
||||||
|
#include <qsgmaterial.h>
|
||||||
|
#include <qsgrendererinterface.h>
|
||||||
|
#include <qsgtexture.h>
|
||||||
|
#include <QtCore/qrunnable.h>
|
||||||
|
|
||||||
|
#include <QtGui/private/qtriangulator_p.h>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
class QuadPath
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void moveTo(const QVector2D &to)
|
||||||
|
{
|
||||||
|
subPathToStart = true;
|
||||||
|
currentPoint = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lineTo(const QVector2D &to)
|
||||||
|
{
|
||||||
|
addElement({}, to, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void quadTo(const QVector2D &control, const QVector2D &to)
|
||||||
|
{
|
||||||
|
addElement(control, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF controlPointRect() const;
|
||||||
|
|
||||||
|
Qt::FillRule fillRule() const { return m_fillRule; }
|
||||||
|
void setFillRule(Qt::FillRule rule) { m_fillRule = rule; }
|
||||||
|
|
||||||
|
void reserve(qsizetype size) { m_elements.reserve(size); }
|
||||||
|
qsizetype elementCount() const { return m_elements.size(); }
|
||||||
|
qsizetype elementCountRecursive() const;
|
||||||
|
|
||||||
|
static QuadPath fromPainterPath(const QPainterPath &path);
|
||||||
|
QPainterPath toPainterPath() const;
|
||||||
|
QuadPath subPathsClosed() const;
|
||||||
|
|
||||||
|
class Element
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Element ()
|
||||||
|
: m_isSubpathStart(false), m_isSubpathEnd(false), m_isLine(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSubpathStart() const
|
||||||
|
{
|
||||||
|
return m_isSubpathStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSubpathEnd() const
|
||||||
|
{
|
||||||
|
return m_isSubpathEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isLine() const
|
||||||
|
{
|
||||||
|
return m_isLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isConvex() const
|
||||||
|
{
|
||||||
|
return m_curvatureFlags & Convex;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector2D startPoint() const
|
||||||
|
{
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector2D controlPoint() const
|
||||||
|
{
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector2D endPoint() const
|
||||||
|
{
|
||||||
|
return ep;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector2D midPoint() const
|
||||||
|
{
|
||||||
|
return isLine() ? 0.5f * (sp + ep) : (0.25f * sp) + (0.5f * cp) + (0.25 * ep);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector3D uvForPoint(QVector2D p) const;
|
||||||
|
|
||||||
|
qsizetype childCount() const { return m_numChildren; }
|
||||||
|
|
||||||
|
qsizetype indexOfChild(qsizetype childNumber) const
|
||||||
|
{
|
||||||
|
Q_ASSERT(childNumber >= 0 && childNumber < childCount());
|
||||||
|
return -(m_firstChildIndex + 1 + childNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector2D pointAtFraction(float t) const;
|
||||||
|
|
||||||
|
QVector2D tangentAtFraction(float t) const
|
||||||
|
{
|
||||||
|
return isLine() ? (ep - sp) : ((1 - t) * 2 * (cp - sp)) + (t * 2 * (ep - cp));
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector2D normalAtFraction(float t) const
|
||||||
|
{
|
||||||
|
const QVector2D tan = tangentAtFraction(t);
|
||||||
|
return QVector2D(-tan.y(), tan.x());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int intersectionsAtY(float y, float *fractions) const;
|
||||||
|
|
||||||
|
enum CurvatureFlags : quint8 {
|
||||||
|
CurvatureUndetermined = 0,
|
||||||
|
FillOnRight = 1,
|
||||||
|
Convex = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
QVector2D sp;
|
||||||
|
QVector2D cp;
|
||||||
|
QVector2D ep;
|
||||||
|
int m_firstChildIndex = 0;
|
||||||
|
quint8 m_numChildren = 0;
|
||||||
|
CurvatureFlags m_curvatureFlags = CurvatureUndetermined;
|
||||||
|
quint8 m_isSubpathStart : 1;
|
||||||
|
quint8 m_isSubpathEnd : 1;
|
||||||
|
quint8 m_isLine : 1;
|
||||||
|
friend class QuadPath;
|
||||||
|
friend QDebug operator<<(QDebug, const QuadPath::Element &);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
void iterateChildrenOf(Element &e, Func &&lambda)
|
||||||
|
{
|
||||||
|
const qsizetype lastChildIndex = e.m_firstChildIndex + e.childCount() - 1;
|
||||||
|
for (qsizetype i = e.m_firstChildIndex; i <= lastChildIndex; i++) {
|
||||||
|
Element &c = m_childElements[i];
|
||||||
|
if (c.childCount() > 0)
|
||||||
|
iterateChildrenOf(c, lambda);
|
||||||
|
else
|
||||||
|
lambda(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
void iterateChildrenOf(const Element &e, Func &&lambda) const
|
||||||
|
{
|
||||||
|
const qsizetype lastChildIndex = e.m_firstChildIndex + e.childCount() - 1;
|
||||||
|
for (qsizetype i = e.m_firstChildIndex; i <= lastChildIndex; i++) {
|
||||||
|
const Element &c = m_childElements[i];
|
||||||
|
if (c.childCount() > 0)
|
||||||
|
iterateChildrenOf(c, lambda);
|
||||||
|
else
|
||||||
|
lambda(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
void iterateElements(Func &&lambda)
|
||||||
|
{
|
||||||
|
for (auto &e : m_elements) {
|
||||||
|
if (e.childCount() > 0)
|
||||||
|
iterateChildrenOf(e, lambda);
|
||||||
|
else
|
||||||
|
lambda(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
void iterateElements(Func &&lambda) const
|
||||||
|
{
|
||||||
|
for (auto &e : m_elements) {
|
||||||
|
if (e.childCount() > 0)
|
||||||
|
iterateChildrenOf(e, lambda);
|
||||||
|
else
|
||||||
|
lambda(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void splitElementAt(qsizetype index);
|
||||||
|
Element &elementAt(qsizetype i) { return i < 0 ? m_childElements[-(i + 1)] : m_elements[i]; }
|
||||||
|
const Element &elementAt(qsizetype i) const
|
||||||
|
{
|
||||||
|
return i < 0 ? m_childElements[-(i + 1)] : m_elements[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
qsizetype indexOfChildAt(qsizetype i, qsizetype childNumber) const
|
||||||
|
{
|
||||||
|
return elementAt(i).indexOfChild(childNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addCurvatureData();
|
||||||
|
bool contains(const QVector2D &v) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addElement(const QVector2D &control, const QVector2D &to, bool isLine = false);
|
||||||
|
Element::CurvatureFlags coordinateOrderOfElement(const Element &element) const;
|
||||||
|
static bool isControlPointOnLeft(const Element &element);
|
||||||
|
static QVector2D closestPointOnLine(const QVector2D &start,
|
||||||
|
const QVector2D &end,
|
||||||
|
const QVector2D &p);
|
||||||
|
static bool isPointOnLeft(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
|
||||||
|
static bool isPointOnLine(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
|
||||||
|
static bool isPointNearLine(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
|
||||||
|
|
||||||
|
friend QDebug operator<<(QDebug, const QuadPath &);
|
||||||
|
|
||||||
|
bool subPathToStart = true;
|
||||||
|
Qt::FillRule m_fillRule = Qt::OddEvenFill;
|
||||||
|
QVector2D currentPoint;
|
||||||
|
QList<Element> m_elements;
|
||||||
|
QList<Element> m_childElements;
|
||||||
|
};
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug, const QuadPath::Element &);
|
||||||
|
QDebug operator<<(QDebug, const QuadPath &);
|
||||||
|
|
||||||
|
class QQuickShapeCurveNode : public QSGNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QQuickShapeCurveNode();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class QQuickShapeCurveRenderer : public QQuickAbstractPathRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QQuickShapeCurveRenderer(QQuickItem *)
|
||||||
|
: m_rootNode(nullptr)
|
||||||
|
{ }
|
||||||
|
~QQuickShapeCurveRenderer() override;
|
||||||
|
|
||||||
|
void beginSync(int totalCount, bool *countChanged) override;
|
||||||
|
void setPath(int index, const QQuickPath *path) override;
|
||||||
|
void setStrokeColor(int index, const QColor &color) override;
|
||||||
|
void setStrokeWidth(int index, qreal w) override;
|
||||||
|
void setFillColor(int index, const QColor &color) override;
|
||||||
|
void setFillRule(int index, QQuickShapePath::FillRule fillRule) override;
|
||||||
|
void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override;
|
||||||
|
void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override;
|
||||||
|
void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
|
||||||
|
qreal dashOffset, const QVector<qreal> &dashPattern) override;
|
||||||
|
void setFillGradient(int index, QQuickShapeGradient *gradient) override;
|
||||||
|
void endSync(bool async) override;
|
||||||
|
void setAsyncCallback(void (*)(void *), void *) override;
|
||||||
|
Flags flags() const override { return Flags{}; }
|
||||||
|
|
||||||
|
void updateNode() override;
|
||||||
|
|
||||||
|
void setRootNode(QQuickShapeCurveNode *node);
|
||||||
|
|
||||||
|
using NodeList = QVector<QSGGeometryNode *>;
|
||||||
|
|
||||||
|
enum DirtyFlag
|
||||||
|
{
|
||||||
|
GeometryDirty = 1,
|
||||||
|
UniformsDirty = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
//### PathData used to be private, but I am using it in a static function. TODO: FIX ###
|
||||||
|
|
||||||
|
struct PathData {
|
||||||
|
|
||||||
|
bool isFillVisible() const { return fillColor.alpha() > 0 || gradientType != NoGradient; }
|
||||||
|
|
||||||
|
bool isStrokeVisible() const
|
||||||
|
{
|
||||||
|
return validPenWidth && pen.color().alpha() > 0 && pen.style() != Qt::NoPen;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool useFragmentShaderStroker() const;
|
||||||
|
|
||||||
|
FillGradientType gradientType = NoGradient;
|
||||||
|
GradientDesc gradient;
|
||||||
|
QPainterPath fillPath;
|
||||||
|
QPainterPath originalPath;
|
||||||
|
QuadPath path;
|
||||||
|
QColor fillColor;
|
||||||
|
Qt::FillRule fillRule = Qt::OddEvenFill;
|
||||||
|
QPen pen;
|
||||||
|
int m_dirty = 0;
|
||||||
|
bool validPenWidth = true;
|
||||||
|
bool convexConcaveResolved = false;
|
||||||
|
|
||||||
|
NodeList fillNodes;
|
||||||
|
NodeList strokeNodes;
|
||||||
|
NodeList debugNodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum DebugVisualizationOption {
|
||||||
|
NoDebug = 0,
|
||||||
|
DebugCurves = 0x01,
|
||||||
|
DebugWireframe = 0x02
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_QUICKSHAPES_PRIVATE_EXPORT static int debugVisualization();
|
||||||
|
Q_QUICKSHAPES_PRIVATE_EXPORT static void setDebugVisualization(int options);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void deleteAndClear(NodeList *nodeList);
|
||||||
|
|
||||||
|
QVector<QSGGeometryNode *> addPathNodesBasic(const PathData &pathData, NodeList *debugNodes);
|
||||||
|
|
||||||
|
QVector<QSGGeometryNode *> addPathNodesDelauneyTest(const PathData &pathData, NodeList *debugNodes);
|
||||||
|
|
||||||
|
QSGGeometryNode *addLoopBlinnNodes(const QTriangleSet &triangles,
|
||||||
|
const QVarLengthArray<quint32> &extraIndices,
|
||||||
|
int startConcaveCurves,
|
||||||
|
const PathData &pathData,
|
||||||
|
NodeList *debugNodes);
|
||||||
|
|
||||||
|
void solveOverlaps(QuadPath &path);
|
||||||
|
|
||||||
|
QQuickShapeCurveNode *m_rootNode;
|
||||||
|
QVector<PathData> m_paths;
|
||||||
|
static int debugVisualizationFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // QQUICKSHAPECURVERENDERER_P_H
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef QQUICKSHAPECURVERENDERER_P_P_H
|
||||||
|
#define QQUICKSHAPECURVERENDERER_P_P_H
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G
|
||||||
|
// -------------
|
||||||
|
//
|
||||||
|
// This file is not part of the Qt API. It exists for the convenience
|
||||||
|
// of a number of Qt sources files. This header file may change from
|
||||||
|
// version to version without notice, or even be removed.
|
||||||
|
//
|
||||||
|
// We mean it.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QtQuickShapes/private/qquickshapesglobal_p.h>
|
||||||
|
#include <QtGui/qvector2d.h>
|
||||||
|
#include <QPainterPath>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(lcShapeCurveRenderer);
|
||||||
|
|
||||||
|
struct QtPathVertex
|
||||||
|
{
|
||||||
|
QVector2D point;
|
||||||
|
int id;
|
||||||
|
quint32 binX = 0;
|
||||||
|
quint32 binY = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QtPathEdge
|
||||||
|
{
|
||||||
|
quint32 startIndex;
|
||||||
|
quint32 endIndex;
|
||||||
|
int id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QtPathTriangle
|
||||||
|
{
|
||||||
|
QtPathTriangle(quint32 i1, quint32 i2, quint32 i3, int d) : v1Index(i1), v2Index(i2), v3Index(i3), id(d) {}
|
||||||
|
quint32 v1Index;
|
||||||
|
quint32 v2Index;
|
||||||
|
quint32 v3Index;
|
||||||
|
|
||||||
|
quint32 adjacentTriangle1 = quint32(-1); // Adjacent to v1-v2
|
||||||
|
quint32 adjacentTriangle2 = quint32(-1); // Adjacent to v2-v3
|
||||||
|
quint32 adjacentTriangle3 = quint32(-1); // Adjacent to v3-v1
|
||||||
|
|
||||||
|
// Used by triangulator
|
||||||
|
quint32 lastSeenVertex = quint32(-1);
|
||||||
|
|
||||||
|
// Should this triangle be rendered? Set to false for triangles connecting to super-triangle
|
||||||
|
bool isValid = true;
|
||||||
|
|
||||||
|
int id;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr bool operator==(const QtPathTriangle& lhs, const QtPathTriangle& rhs)
|
||||||
|
{
|
||||||
|
return lhs.id == rhs.id
|
||||||
|
&& lhs.v1Index == rhs.v1Index
|
||||||
|
&& lhs.v2Index == rhs.v2Index
|
||||||
|
&& lhs.v3Index == rhs.v3Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QBezier;
|
||||||
|
Q_QUICKSHAPES_PRIVATE_EXPORT QPolygonF qt_toQuadratics(const QBezier &b, qreal errorLimit = 0.2);
|
||||||
|
Q_QUICKSHAPES_PRIVATE_EXPORT QList<QtPathTriangle> qtDelaunayTriangulator(const QList<QtPathVertex> &vertices, const QList<QtPathEdge> &edges, const QPainterPath &path);
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif //QQUICKSHAPECURVERENDERER_P_P_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,139 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||||
|
|
||||||
|
// ---------------- Cubic -> Quadratic path stuff - temporarily here -----------
|
||||||
|
|
||||||
|
#include <private/qbezier_p.h>
|
||||||
|
#include <QtMath>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static bool qt_isQuadratic(const QBezier &b)
|
||||||
|
{
|
||||||
|
const qreal f = 3.0 / 2.0;
|
||||||
|
const QPointF c1 = b.pt1() + f * (b.pt2() - b.pt1());
|
||||||
|
const QPointF c2 = b.pt4() + f * (b.pt3() - b.pt4());
|
||||||
|
return c1 == c2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static qreal qt_scoreQuadratic(const QBezier &b, QPointF qcp)
|
||||||
|
{
|
||||||
|
// Construct a cubic from the quadratic, and compare its control points to the originals'
|
||||||
|
const QRectF bounds = b.bounds();
|
||||||
|
qreal dim = QLineF(bounds.topLeft(), bounds.bottomRight()).length();
|
||||||
|
if (qFuzzyIsNull(dim))
|
||||||
|
return 0;
|
||||||
|
const qreal f = 2.0 / 3;
|
||||||
|
const QPointF cp1 = b.pt1() + f * (qcp - b.pt1());
|
||||||
|
const QPointF cp2 = b.pt4() + f * (qcp - b.pt4());
|
||||||
|
const QLineF d1(b.pt2(), cp1);
|
||||||
|
const QLineF d2(b.pt3(), cp2);
|
||||||
|
return qMax(d1.length(), d2.length()) / dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qreal qt_quadraticForCubic(const QBezier &b, QPointF *qcp)
|
||||||
|
{
|
||||||
|
const QLineF st = b.startTangent();
|
||||||
|
const QLineF et = b.endTangent();
|
||||||
|
if (st.intersects(et, qcp) == QLineF::NoIntersection)
|
||||||
|
*qcp = b.midPoint();
|
||||||
|
return qt_scoreQuadratic(b, *qcp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qt_getInflectionPoints(const QBezier &orig, qreal *tpoints)
|
||||||
|
{
|
||||||
|
auto isValidRoot = [](qreal r) {
|
||||||
|
return qIsFinite(r) && (r > 0) && (!qFuzzyIsNull(float(r))) && (r < 1)
|
||||||
|
&& (!qFuzzyIsNull(float(r - 1)));
|
||||||
|
};
|
||||||
|
|
||||||
|
// normalize so pt1.x,pt1.y,pt4.y == 0
|
||||||
|
QTransform xf;
|
||||||
|
const QLineF l(orig.pt1(), orig.pt4());
|
||||||
|
xf.rotate(l.angle());
|
||||||
|
xf.translate(-orig.pt1().x(), -orig.pt1().y());
|
||||||
|
const QBezier n = orig.mapBy(xf);
|
||||||
|
Q_ASSERT(n.pt1() == QPoint() && qFuzzyIsNull(float(n.pt4().y())));
|
||||||
|
|
||||||
|
const qreal p = n.pt3().x() * n.pt2().y();
|
||||||
|
const qreal q = n.pt4().x() * n.pt2().y();
|
||||||
|
const qreal r = n.pt2().x() * n.pt3().y();
|
||||||
|
const qreal s = n.pt4().x() * n.pt3().y();
|
||||||
|
|
||||||
|
const qreal a = 36 * ((-3 * p) + (2 * q) + (3 * r) - s);
|
||||||
|
if (!a)
|
||||||
|
return 0;
|
||||||
|
const qreal b = -18 * (((3 * p) - q) - (3 * r));
|
||||||
|
const qreal c = 18 * (r - p);
|
||||||
|
const qreal rad = (b * b) - (2 * a * c);
|
||||||
|
if (rad < 0)
|
||||||
|
return 0;
|
||||||
|
const qreal sqr = qSqrt(rad);
|
||||||
|
const qreal root1 = (b + sqr) / a;
|
||||||
|
const qreal root2 = (b - sqr) / a;
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
if (isValidRoot(root1))
|
||||||
|
tpoints[res++] = root1;
|
||||||
|
if (root2 != root1 && isValidRoot(root2))
|
||||||
|
tpoints[res++] = root2;
|
||||||
|
|
||||||
|
if (res == 2 && tpoints[0] > tpoints[1])
|
||||||
|
qSwap(tpoints[0], tpoints[1]);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qt_addToQuadratics(const QBezier &b, QPolygonF *p, qreal spanlength, qreal errorLimit)
|
||||||
|
{
|
||||||
|
Q_ASSERT((spanlength > 0) && !(spanlength > 1));
|
||||||
|
|
||||||
|
QPointF qcp;
|
||||||
|
bool isOk = (qt_quadraticForCubic(b, &qcp) < errorLimit); // error limit, careful
|
||||||
|
if (isOk || spanlength < 0.1) {
|
||||||
|
p->append(qcp);
|
||||||
|
p->append(b.pt4());
|
||||||
|
} else {
|
||||||
|
QBezier rhs = b;
|
||||||
|
QBezier lhs;
|
||||||
|
rhs.parameterSplitLeft(0.5, &lhs);
|
||||||
|
qt_addToQuadratics(lhs, p, spanlength / 2, errorLimit);
|
||||||
|
qt_addToQuadratics(rhs, p, spanlength / 2, errorLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPolygonF qt_toQuadratics(const QBezier &b, qreal errorLimit)
|
||||||
|
{
|
||||||
|
|
||||||
|
QPolygonF res;
|
||||||
|
res.reserve(16);
|
||||||
|
res.append(b.pt1());
|
||||||
|
const QRectF cpr = b.bounds();
|
||||||
|
qreal epsilon = QLineF(cpr.topLeft(), cpr.bottomRight()).length() * 0.5 * errorLimit;
|
||||||
|
bool degenerate = false;
|
||||||
|
if (QLineF(b.pt2(), b.pt1()).length() < epsilon) {
|
||||||
|
res.append(b.pt3());
|
||||||
|
degenerate = true;
|
||||||
|
} else if (QLineF(b.pt4(), b.pt3()).length() < epsilon) {
|
||||||
|
res.append(b.pt2());
|
||||||
|
degenerate = true;
|
||||||
|
}
|
||||||
|
if (degenerate) {
|
||||||
|
res.append(b.pt4());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
qreal infPoints[2];
|
||||||
|
int numInfPoints = qt_getInflectionPoints(b, infPoints);
|
||||||
|
qreal t0 = 0;
|
||||||
|
for (int i = 0; i < numInfPoints + 1; i++) { // #segments == #inflectionpoints + 1
|
||||||
|
qreal t1 = (i < numInfPoints) ? infPoints[i] : 1;
|
||||||
|
QBezier segment = b.bezierOnInterval(t0, t1);
|
||||||
|
qt_addToQuadratics(segment, &res, t1 - t0, errorLimit);
|
||||||
|
t0 = t1;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
|
@ -0,0 +1,108 @@
|
||||||
|
#version 440
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 qt_TexCoord;
|
||||||
|
layout(location = 1) in vec4 debugColor;
|
||||||
|
|
||||||
|
#if defined(LINEARGRADIENT)
|
||||||
|
layout(location = 2) in float gradTabIndex;
|
||||||
|
#elif defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
|
||||||
|
layout(location = 2) in vec2 coord;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform buf {
|
||||||
|
mat4 qt_Matrix;
|
||||||
|
|
||||||
|
#if defined(STROKE)
|
||||||
|
vec4 strokeColor;
|
||||||
|
float strokeWidth;
|
||||||
|
float reserved1;
|
||||||
|
float reserved2;
|
||||||
|
float reserved3;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(LINEARGRADIENT)
|
||||||
|
vec2 gradientStart;
|
||||||
|
vec2 gradientEnd;
|
||||||
|
#elif defined(RADIALGRADIENT)
|
||||||
|
vec2 translationPoint;
|
||||||
|
vec2 focalToCenter;
|
||||||
|
float centerRadius;
|
||||||
|
float focalRadius;
|
||||||
|
#elif defined(CONICALGRADIENT)
|
||||||
|
vec2 translationPoint;
|
||||||
|
float angle;
|
||||||
|
#else
|
||||||
|
vec4 color;
|
||||||
|
#endif
|
||||||
|
} ubuf;
|
||||||
|
|
||||||
|
#define INVERSE_2PI 0.1591549430918953358
|
||||||
|
|
||||||
|
#if defined(LINEARGRADIENT) || defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
|
||||||
|
layout(binding = 1) uniform sampler2D gradTabTexture;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vec4 baseColor()
|
||||||
|
{
|
||||||
|
#if defined(LINEARGRADIENT)
|
||||||
|
return texture(gradTabTexture, vec2(gradTabIndex, 0.5));
|
||||||
|
#elif defined(RADIALGRADIENT)
|
||||||
|
float rd = ubuf.centerRadius - ubuf.focalRadius;
|
||||||
|
float b = 2.0 * (rd * ubuf.focalRadius + dot(coord, ubuf.focalToCenter));
|
||||||
|
float fmp2_m_radius2 = -ubuf.focalToCenter.x * ubuf.focalToCenter.x - ubuf.focalToCenter.y * ubuf.focalToCenter.y + rd * rd;
|
||||||
|
float inverse_2_fmp2_m_radius2 = 1.0 / (2.0 * fmp2_m_radius2);
|
||||||
|
float det = b * b - 4.0 * fmp2_m_radius2 * ((ubuf.focalRadius * ubuf.focalRadius) - dot(coord, coord));
|
||||||
|
vec4 result = vec4(0.0);
|
||||||
|
if (det >= 0.0) {
|
||||||
|
float detSqrt = sqrt(det);
|
||||||
|
float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2);
|
||||||
|
if (ubuf.focalRadius + w * (ubuf.centerRadius - ubuf.focalRadius) >= 0.0)
|
||||||
|
result = texture(gradTabTexture, vec2(w, 0.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
#elif defined(CONICALGRADIENT)
|
||||||
|
float t;
|
||||||
|
if (abs(coord.y) == abs(coord.x))
|
||||||
|
t = (atan(-coord.y + 0.002, coord.x) + ubuf.angle) * INVERSE_2PI;
|
||||||
|
else
|
||||||
|
t = (atan(-coord.y, coord.x) + ubuf.angle) * INVERSE_2PI;
|
||||||
|
return texture(gradTabTexture, vec2(t - floor(t), 0.5));
|
||||||
|
#else
|
||||||
|
return vec4(ubuf.color.rgb, 1.0) * ubuf.color.a;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float f = qt_TexCoord.z * (qt_TexCoord.x * qt_TexCoord.x - qt_TexCoord.y) // curve
|
||||||
|
+ (1.0 - abs(qt_TexCoord.z)) * (qt_TexCoord.x - qt_TexCoord.y); // line
|
||||||
|
|
||||||
|
#if defined(STROKE)
|
||||||
|
float _ddx = dFdx(f);
|
||||||
|
float _ddy = dFdy(f);
|
||||||
|
float df = length(vec2(_ddx, _ddy));
|
||||||
|
float distance = (f / df); // distance from centre of fragment to line
|
||||||
|
|
||||||
|
float halfStrokeWidth = ubuf.strokeWidth / 2.0;
|
||||||
|
|
||||||
|
// calculate stroke
|
||||||
|
float strokeCoverage = 1.0 - clamp(0.5 + abs(distance) - halfStrokeWidth, 0.0, 1.0);
|
||||||
|
vec4 stroke = ubuf.strokeColor * strokeCoverage;
|
||||||
|
|
||||||
|
float fillCoverage = clamp(0.5 + f / df, 0.0, 1.0);
|
||||||
|
vec4 fill = baseColor() * fillCoverage;
|
||||||
|
|
||||||
|
vec4 combined = fill * (1.0 - stroke.a) + stroke * stroke.a;
|
||||||
|
|
||||||
|
// finally mix in debug
|
||||||
|
fragColor = mix(combined, vec4(debugColor.rgb, 1.0), debugColor.a);
|
||||||
|
|
||||||
|
// TODO: support both outline and fill
|
||||||
|
#else
|
||||||
|
float df = fwidth(f);
|
||||||
|
fragColor = mix(baseColor() * clamp(0.5 + f / df, 0.0, 1.0), vec4(debugColor.rgba), debugColor.a);
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
#version 440
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 vertexCoord;
|
||||||
|
layout(location = 1) in vec3 vertexTexCoord;
|
||||||
|
layout(location = 2) in vec4 vertexDebugColor;
|
||||||
|
|
||||||
|
layout(location = 0) out vec3 qt_TexCoord;
|
||||||
|
layout(location = 1) out vec4 debugColor;
|
||||||
|
|
||||||
|
#if defined(LINEARGRADIENT)
|
||||||
|
layout(location = 2) out float gradTabIndex;
|
||||||
|
#elif defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
|
||||||
|
layout(location = 2) out vec2 coord;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform buf {
|
||||||
|
mat4 qt_Matrix;
|
||||||
|
|
||||||
|
#if defined(STROKE)
|
||||||
|
vec4 strokeColor;
|
||||||
|
float strokeWidth;
|
||||||
|
float reserved1;
|
||||||
|
float reserved2;
|
||||||
|
float reserved3;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(LINEARGRADIENT)
|
||||||
|
vec2 gradientStart;
|
||||||
|
vec2 gradientEnd;
|
||||||
|
#elif defined(RADIALGRADIENT)
|
||||||
|
vec2 translationPoint;
|
||||||
|
vec2 focalToCenter;
|
||||||
|
float centerRadius;
|
||||||
|
float focalRadius;
|
||||||
|
#elif defined(CONICALGRADIENT)
|
||||||
|
vec2 translationPoint;
|
||||||
|
float angle;
|
||||||
|
#else
|
||||||
|
vec4 color;
|
||||||
|
#endif
|
||||||
|
} ubuf;
|
||||||
|
|
||||||
|
out gl_PerVertex { vec4 gl_Position; };
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
qt_TexCoord = vertexTexCoord;
|
||||||
|
debugColor = vertexDebugColor;
|
||||||
|
|
||||||
|
#if defined(LINEARGRADIENT)
|
||||||
|
vec2 gradVec = ubuf.gradientEnd - ubuf.gradientStart;
|
||||||
|
gradTabIndex = dot(gradVec, vertexCoord.xy - ubuf.gradientStart.xy) / dot(gradVec, gradVec);
|
||||||
|
#elif defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
|
||||||
|
coord = vertexCoord.xy - ubuf.translationPoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gl_Position = ubuf.qt_Matrix * vertexCoord;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#version 440
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
layout(location = 0) in vec3 barycentric;
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform buf {
|
||||||
|
mat4 qt_Matrix;
|
||||||
|
} ubuf;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float f = min(barycentric.x, min(barycentric.y, barycentric.z));
|
||||||
|
float d = fwidth(f * 1.5);
|
||||||
|
float alpha = smoothstep(0.0, d, f);
|
||||||
|
|
||||||
|
//alpha = 1.0 - step(0.5, barycentric.x);
|
||||||
|
fragColor = vec4(1.0, 0.2, 1.0, 1.0) * (1.0 - alpha);
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#version 440
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 vertexCoord;
|
||||||
|
layout(location = 1) in vec3 vertexBarycentric;
|
||||||
|
layout(location = 0) out vec3 barycentric;
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform buf {
|
||||||
|
mat4 qt_Matrix;
|
||||||
|
} ubuf;
|
||||||
|
|
||||||
|
out gl_PerVertex { vec4 gl_Position; };
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
barycentric = vertexBarycentric;
|
||||||
|
gl_Position = ubuf.qt_Matrix * vertexCoord;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="498" height="450" viewBox="0, 0, 498, 450">
|
||||||
|
<g id="Layer_1">
|
||||||
|
<path d="M377.478,156.433 C390.511,164.689 405.743,177.699 401.901,188.702 L400.821,214.061 L387.401,200.274 C377.97,203.879 355.363,209.091 344.882,209.309 C327.622,209.086 318.23,200.447 301.246,210.607 L300.15,211.261 C287.503,219.529 278.841,222.432 261.924,220.372 C240.649,217.635 222.088,219.976 200.944,221.401 C189.111,222.851 186.176,229.895 185.117,238.294 C184.679,248.402 186.989,251.163 188.144,259.871 C189.694,271.542 180.447,281.398 175.785,292.36 C171.836,302.716 170.28,317.969 170.783,332.682 L350.629,302.414 L497.063,442.618 L439.68,448.335 L171.109,338.724 C171.796,348.056 173.32,356.85 175.59,363.646 C180.514,378.376 199.634,392.772 200.249,404.625 C200.896,417.212 187.414,419.239 174.601,416.362 C155.05,411.713 154.299,415.621 141.357,426.569 C113.335,450.279 98.118,429.304 71.605,431.841 C55.253,433.405 40.729,432.918 27.507,424.542 C16.53,416.991 17.367,406.636 15.482,396.464 C14.067,388.824 15.899,382.701 25.702,379.28 C39.023,376.32 56.656,378.437 65.04,370.918 C74.247,362.664 72.98,362.849 84.625,355.865 C105.108,343.576 98.591,331.952 98.436,313.869 C98.388,308.464 98.797,303.473 99.42,298.096 C101.462,281.407 101.799,265.05 101.034,248.311 C100.788,243.23 100.462,237.986 98.094,233.185 C86.734,214.876 67.777,210.151 74.41,184.825 C83.029,151.909 117.925,169.13 136.27,162.996 C147.594,159.208 152.842,157.385 165.027,154.781 C169.689,153.785 174.381,152.847 179.057,151.883 C191.796,149.238 202.615,147.549 215.653,146.058 C237.815,143.521 239.756,129.349 272.799,126.685 C294.042,124.898 292.304,121.222 309.264,115.415 C330.998,107.974 345.932,115.338 355.323,130.552 C363.442,143.706 362.125,146.461 377.478,156.433" fill="#D0CFCA"/>
|
||||||
|
<path d="M439.68,210.512 L439.68,448.335 L0.464,341.45 L0.464,103.627 L210.167,90.042 L439.68,210.512" fill="#DFB142"/>
|
||||||
|
<path d="M0.464,103.627 C53.025,50.996 164.147,14.658 292.833,14.465 L439.68,210.512 L0.464,103.627" fill="#F0C55C"/>
|
||||||
|
<path d="M439.68,272.823 L439.68,379.792 L0.464,272.907 L0.464,165.939 L439.68,272.823" fill="#685227"/>
|
||||||
|
<path d="M362.421,63.072 C375.451,73.881 390.685,90.917 386.843,105.325 L385.763,138.531 L372.343,120.479 C362.913,125.199 340.305,132.023 329.822,132.31 C312.565,132.018 303.174,120.703 286.188,134.008 L285.091,134.866 C272.443,145.693 263.784,149.494 246.864,146.795 C225.593,143.212 207.028,146.279 185.882,148.143 C174.055,150.042 171.114,159.266 170.059,170.264 C169.617,183.499 171.93,187.117 173.087,198.519 C174.633,213.801 165.388,226.707 160.726,241.06 C153.682,265.245 154.256,309.816 160.533,334.409 C165.455,353.698 184.577,372.548 185.187,388.07 C185.839,404.551 172.354,407.205 159.541,403.436 C139.991,397.352 139.242,402.465 126.298,416.803 C98.275,447.852 83.059,420.385 56.547,423.705 C40.193,425.756 25.669,425.118 12.448,414.151 C1.472,404.259 2.308,390.702 0.423,377.381 C-0.993,367.375 0.84,359.362 10.644,354.877 C23.964,351.004 41.596,353.777 49.98,343.931 C59.186,333.122 57.921,333.366 69.564,324.218 C90.05,308.127 83.529,292.907 83.374,269.229 C83.331,262.151 83.737,255.615 84.363,248.573 C86.4,226.719 86.737,205.301 85.978,183.381 C85.73,176.728 85.403,169.861 83.034,163.574 C71.676,139.599 52.721,133.411 59.351,100.248 C67.97,57.145 102.863,79.697 121.208,71.664 C132.535,66.704 137.782,64.318 149.968,60.907 C154.63,59.602 159.322,58.374 163.998,57.113 C176.736,53.648 187.556,51.437 200.594,49.483 C222.753,46.163 224.694,27.604 257.742,24.117 C278.982,21.776 277.247,16.962 294.207,9.359 C315.939,-0.384 330.873,9.258 340.265,29.18 C348.384,46.406 347.065,50.012 362.421,63.072" fill="#A02529"/>
|
||||||
|
<path d="M377.222,77.803 C384.346,86.596 389.209,96.457 386.843,105.325 L385.763,138.531 L372.343,120.479 C362.913,125.199 340.305,132.023 329.822,132.31 C312.565,132.018 303.174,120.703 286.188,134.008 L285.091,134.866 C272.443,145.693 263.784,149.494 246.864,146.795 C225.593,143.212 207.028,146.279 185.882,148.143 C174.055,150.042 171.114,159.266 170.059,170.264 C169.617,183.499 171.93,187.117 173.087,198.519 C174.633,213.801 165.388,226.707 160.726,241.06 C153.682,265.245 154.256,309.816 160.533,334.409 C165.455,353.698 184.577,372.548 185.187,388.07 C185.839,404.551 172.354,407.205 159.541,403.436 C139.991,397.352 139.242,402.465 126.298,416.803 C98.275,447.852 83.059,420.385 56.547,423.705 C41.406,425.604 27.835,425.198 15.41,416.418 C15.886,416.252 16.353,416.086 16.806,415.923 C40.174,407.529 48.443,396.154 76.787,401.466 C98.441,405.379 98.762,406.43 114.283,392.336 C122.29,385.065 130.835,382.674 136.828,376.579 C147.786,365.44 143.055,348.134 141.242,333.961 C139.79,322.607 138.545,311.693 137.868,300.247 C136.302,270.394 136.149,249.273 146.169,220.601 C156.699,185.664 142.878,187.253 136.676,158.625 C133.559,140.425 141.91,130.414 159.322,126.454 C174.809,123.09 185.026,122.958 200.438,117.255 C226.389,107.653 237.86,126.159 267.655,111.396 C290.299,100.173 288,101.231 313.813,100.553 C322.81,100.316 331.664,100.323 340.66,100.543 C354.877,100.939 372.706,99.879 376.406,83.305 C376.799,81.544 377.061,79.698 377.222,77.803" fill="#852124"/>
|
||||||
|
<path d="M116.994,372.295 C96.441,393.218 85.04,378.461 60.386,384.618 C41.425,389.804 40.515,394.084 19.935,387.145 C-2.438,379.129 8.007,369.233 23.439,362.447 C35.36,357.424 45.017,353.945 56.672,347.815 C66.414,342.692 74.814,340.533 84.187,336.313 C95.931,330.505 89.501,323.825 91.833,310.488 C97.182,279.909 97.906,262.688 96.68,231.982 C96.449,226.215 93.495,190.875 105.333,195.129 C112.567,197.728 113.875,226.189 114.663,233.57 C116.893,254.394 116.754,269.973 116.572,290.65 C116.391,311.867 117.946,313.248 125.413,333.1 C131.815,350.125 129.549,358.997 116.994,372.295 z M277.376,26.93 C256.4,34.431 249.969,33.482 233.64,49.962 C224.443,59.24 216.728,61.36 203.788,61.262 C187.182,60.92 176.702,55.995 160.816,63.608 C158.592,64.676 156.373,65.745 154.144,66.805 C141.264,72.87 114.971,74.232 107.809,85.082 C102.256,93.498 109.541,98.832 117.668,100.211 C132.249,102.681 153.315,101.858 167.441,97.815 C195.955,89.668 202.928,88.077 232.115,95.399 C252.075,98.504 255.43,86.181 270.652,77.257 C290.588,65.572 311.159,75.362 332.33,74.141 C343.4,73.555 354.434,70.833 345.116,57.437 C340.157,50.307 328.218,41.032 321.232,33.358 C305.834,16.439 297.153,19.871 277.376,26.93" fill="#BB242A"/>
|
||||||
|
<path d="M213.284,102.237 C235.308,102.237 253.268,93.724 253.268,83.285 C253.268,72.846 235.308,64.331 213.284,64.331 C191.261,64.331 173.301,72.846 173.301,83.285 C173.301,93.724 191.261,102.237 213.284,102.237" fill="#A02529"/>
|
||||||
|
<path d="M296.932,67.335 C315.226,67.335 330.146,60.262 330.146,51.591 C330.146,42.919 315.226,35.846 296.932,35.846 C278.638,35.846 263.715,42.919 263.715,51.591 C263.715,60.262 278.638,67.335 296.932,67.335" fill="#A02529"/>
|
||||||
|
<path d="M271.697,1.555 C274.782,1.555 277.761,2.011 280.573,2.854 C283.386,2.011 286.366,1.555 289.454,1.555 C306.489,1.555 320.297,15.363 320.297,32.398 C320.297,49.431 306.489,63.239 289.454,63.239 C286.366,63.239 283.386,62.784 280.573,61.94 C277.761,62.784 274.782,63.239 271.697,63.239 C254.663,63.239 240.854,49.431 240.854,32.398 C240.854,15.363 254.663,1.555 271.697,1.555" fill="#852124"/>
|
||||||
|
<path d="M300.104,3.445 C311.89,7.783 320.297,19.108 320.297,32.398 C320.297,49.431 306.489,63.239 289.454,63.239 C286.366,63.239 283.386,62.784 280.573,61.94 C277.761,62.784 274.782,63.239 271.697,63.239 C257.32,63.239 245.242,53.405 241.822,40.097 C251.466,53.606 263.565,57.28 278.381,50.083 C312.573,61.654 325.556,25.161 300.104,3.445" fill="#61191B"/>
|
||||||
|
<path d="M297.153,16.662 C294.196,13.79 290.182,11.311 285.934,11.371 C279.467,11.465 279.824,12.683 273.232,9.94 C269.746,8.489 266.511,8.766 262.892,9.656 C257.742,10.921 253.609,13.591 250.145,17.573 C243.862,25.22 245.932,33.326 255.406,36.683 L256.029,36.902 C258.651,37.773 266.73,40.311 268.992,39.858 C273.745,38.905 276.231,33.803 282.086,37.96 C286.883,41.431 287.62,43.618 294.196,42.936 C297.701,42.379 299.156,39.906 300.562,36.849 C303.38,30.721 302.722,23.53 298.527,18.185 C298.084,17.63 297.646,17.174 297.153,16.662" fill="#A02529"/>
|
||||||
|
<path d="M182.906,23.052 C186.623,23.052 190.21,23.601 193.595,24.617 C196.982,23.601 200.567,23.052 204.283,23.052 C224.79,23.052 241.411,39.675 241.411,60.179 C241.411,80.684 224.79,97.306 204.283,97.306 C200.567,97.306 196.982,96.758 193.595,95.742 C190.21,96.758 186.623,97.306 182.906,97.306 C162.401,97.306 145.778,80.684 145.778,60.179 C145.778,39.675 162.401,23.052 182.906,23.052" fill="#852124"/>
|
||||||
|
<path d="M217.107,25.326 C231.292,30.548 241.411,44.182 241.411,60.179 C241.411,80.684 224.79,97.306 204.283,97.306 C200.567,97.306 196.982,96.758 193.595,95.742 C190.21,96.758 186.623,97.306 182.906,97.306 C165.602,97.306 151.064,85.468 146.947,69.449 L146.947,69.448 C158.552,85.71 173.119,90.133 190.956,81.469 C232.115,95.399 247.744,51.467 217.107,25.326" fill="#61191B"/>
|
||||||
|
<path d="M213.552,41.237 C209.99,37.779 205.16,34.796 200.046,34.87 C192.261,34.98 192.691,36.448 184.757,33.146 C180.557,31.397 176.667,31.732 172.31,32.804 C166.109,34.328 161.138,37.54 156.962,42.333 C149.401,51.538 151.893,61.298 163.298,65.338 L164.046,65.602 C167.206,66.649 176.932,69.705 179.65,69.159 C185.374,68.012 188.365,61.87 195.415,66.875 C201.189,71.055 202.077,73.687 209.996,72.866 C214.212,72.195 215.963,69.218 217.655,65.538 C221.048,58.161 220.254,49.505 215.209,43.07 C214.669,42.402 214.146,41.853 213.552,41.237" fill="#A02529"/>
|
||||||
|
<path d="M88.513,390.871 C110.533,390.871 128.495,382.359 128.495,371.918 C128.495,361.479 110.533,352.964 88.513,352.964 C66.489,352.964 48.529,361.479 48.529,371.918 C48.529,382.359 66.489,390.871 88.513,390.871" fill="#A02529"/>
|
||||||
|
<path d="M58.132,311.686 C61.848,311.686 65.436,312.234 68.82,313.249 C72.207,312.234 75.795,311.686 79.511,311.686 C100.016,311.686 116.639,328.307 116.639,348.812 C116.639,369.319 100.016,385.942 79.511,385.942 C75.795,385.942 72.207,385.391 68.82,384.375 C65.436,385.391 61.848,385.942 58.132,385.942 C37.629,385.942 21.006,369.319 21.006,348.812 C21.006,328.307 37.629,311.686 58.132,311.686" fill="#852124"/>
|
||||||
|
<path d="M92.335,313.96 C106.521,319.182 116.639,332.816 116.639,348.812 C116.639,369.319 100.016,385.942 79.511,385.942 C75.795,385.942 72.207,385.391 68.82,384.375 C65.436,385.391 61.848,385.942 58.132,385.942 C40.828,385.942 26.289,374.101 22.174,358.082 C33.779,374.344 48.345,378.766 66.182,370.103 C107.344,384.033 122.97,340.101 92.335,313.96" fill="#61191B"/>
|
||||||
|
<path d="M88.779,329.871 C85.219,326.413 80.385,323.43 75.273,323.502 C67.489,323.615 67.919,325.082 59.982,321.779 C55.785,320.031 51.893,320.367 47.535,321.437 C41.339,322.96 36.362,326.173 32.19,330.967 C24.628,340.172 27.119,349.932 38.524,353.97 L39.272,354.237 C42.432,355.284 52.159,358.339 54.876,357.793 C60.602,356.645 63.591,350.503 70.641,355.509 C76.418,359.689 77.303,362.32 85.222,361.498 C89.438,360.827 91.188,357.851 92.881,354.171 C96.273,346.794 95.481,338.137 90.435,331.702 C89.898,331.035 89.373,330.488 88.779,329.871" fill="#A02529"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,65 @@
|
||||||
|
# Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
qt_internal_add_manual_test(painterPathQuickShape
|
||||||
|
GUI
|
||||||
|
SOURCES
|
||||||
|
main.cpp
|
||||||
|
debugpaintitem.h debugpaintitem.cpp
|
||||||
|
svgpathloader.h svgpathloader.cpp
|
||||||
|
debugvisualizationcontroller.h debugvisualizationcontroller.cpp
|
||||||
|
LIBRARIES
|
||||||
|
Qt::Gui
|
||||||
|
Qt::Qml
|
||||||
|
Qt::Quick
|
||||||
|
Qt::QuickPrivate
|
||||||
|
Qt::QuickShapesPrivate
|
||||||
|
Qt::SvgPrivate
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
set(qml_resource_files
|
||||||
|
"1535737773.svg"
|
||||||
|
"main.qml"
|
||||||
|
"SvgShape.qml"
|
||||||
|
"ControlPanel.qml"
|
||||||
|
"ControlPoint.qml"
|
||||||
|
"TextShape.qml"
|
||||||
|
"SimpleShape.qml"
|
||||||
|
"SmallPolygon.qml"
|
||||||
|
"Squircle.qml"
|
||||||
|
"ControlledShape.qml"
|
||||||
|
"Graziano.ttf"
|
||||||
|
"CubicShape.qml"
|
||||||
|
"hand-print.svg"
|
||||||
|
"background.png"
|
||||||
|
"arcDirection.qml"
|
||||||
|
"arcRotation.qml"
|
||||||
|
"capStyles.qml"
|
||||||
|
"cubicCurve.qml"
|
||||||
|
"dashPattern.qml"
|
||||||
|
"ellipticalArcs.qml"
|
||||||
|
"fillRules.qml"
|
||||||
|
"gradientSpreadModes.qml"
|
||||||
|
"joinStyles.qml"
|
||||||
|
"largeOrSmallArc.qml"
|
||||||
|
"linearGradient.qml"
|
||||||
|
"quadraticCurve.qml"
|
||||||
|
"radialGradient.qml"
|
||||||
|
"strokeOrFill.qml"
|
||||||
|
"text.qml"
|
||||||
|
"tiger.qml"
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_internal_add_resource(painterPathQuickShape "qml"
|
||||||
|
PREFIX
|
||||||
|
"/"
|
||||||
|
FILES
|
||||||
|
${qml_resource_files}
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_add_qml_module(painterPathQuickShape
|
||||||
|
VERSION 1.0
|
||||||
|
URI InstancingTest
|
||||||
|
RESOURCE_PREFIX /
|
||||||
|
)
|
|
@ -0,0 +1,281 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import QtQuick.Dialogs
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property real scale: +scaleSlider.value.toFixed(4)
|
||||||
|
property color outlineColor: enableOutline.checked ? Qt.rgba(outlineColor.color.r, outlineColor.color.g, outlineColor.color.b, pathAlpha) : Qt.rgba(0,0,0,0)
|
||||||
|
property color fillColor: Qt.rgba(fillColor.color.r, fillColor.color.g, fillColor.color.b, pathAlpha)
|
||||||
|
property alias pathAlpha: alphaSlider.value
|
||||||
|
property alias outlineWidth: outlineWidth.value
|
||||||
|
property alias outlineStyle: outlineStyle.currentValue
|
||||||
|
property alias capStyle: capStyle.currentValue
|
||||||
|
property alias joinStyle: joinStyle.currentValue
|
||||||
|
property alias debugCurves: enableDebug.checked
|
||||||
|
property alias debugWireframe: enableWireframe.checked
|
||||||
|
property alias painterComparison: painterComparison.currentIndex
|
||||||
|
property alias painterComparisonColor: painterComparisonColor.color
|
||||||
|
property alias painterComparisonAlpha: painterComparisonColorAlpha.value
|
||||||
|
property alias outlineEnabled: enableOutline.checked
|
||||||
|
property alias gradientType: gradientType.currentIndex
|
||||||
|
property alias rendererName: rendererLabel.text
|
||||||
|
property alias preferCurve: rendererLabel.preferCurve
|
||||||
|
|
||||||
|
property int subShape: pickSubShape.checked ? subShapeSelector.value : -1
|
||||||
|
|
||||||
|
property real pathMargin: 150
|
||||||
|
|
||||||
|
function setScale(x) {
|
||||||
|
scaleSlider.value = x
|
||||||
|
}
|
||||||
|
|
||||||
|
signal pathChanged
|
||||||
|
function updatePath()
|
||||||
|
{
|
||||||
|
pathChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 10
|
||||||
|
RowLayout {
|
||||||
|
Label {
|
||||||
|
text: "Renderer:"
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
id: rendererLabel
|
||||||
|
property bool preferCurve: true
|
||||||
|
color: "white"
|
||||||
|
text: "Unknown"
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: {
|
||||||
|
rendererLabel.preferCurve = !rendererLabel.preferCurve
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CheckBox { id: enableDebug }
|
||||||
|
Label {
|
||||||
|
text: "Debug"
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
CheckBox { id: enableWireframe }
|
||||||
|
Label {
|
||||||
|
text: "Wireframe"
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
ComboBox {
|
||||||
|
id: painterComparison
|
||||||
|
model: [
|
||||||
|
"No QPainter comparison",
|
||||||
|
"Overlaid QPainter comparison",
|
||||||
|
"Underlaid QPainter comparison"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: painterComparisonColor
|
||||||
|
color: "red"
|
||||||
|
width: 20
|
||||||
|
height: 20
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
painterComparisonColorDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Slider {
|
||||||
|
id: painterComparisonColorAlpha
|
||||||
|
from: 0.0
|
||||||
|
to: 1.0
|
||||||
|
value: 1.0
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: "Alpha"
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
CheckBox { id: pickSubShape }
|
||||||
|
Label {
|
||||||
|
text: "Pick SVG sub-shape"
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
SpinBox {
|
||||||
|
id: subShapeSelector
|
||||||
|
visible: pickSubShape.checked
|
||||||
|
value: 0
|
||||||
|
to: 999
|
||||||
|
editable: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
Label {
|
||||||
|
text: "Scale:"
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: scaleEdit
|
||||||
|
text: scaleSlider.value.toFixed(4)
|
||||||
|
onEditingFinished: {
|
||||||
|
let val = +text
|
||||||
|
if (val > 0)
|
||||||
|
scaleSlider.value = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Slider {
|
||||||
|
id: scaleSlider
|
||||||
|
Layout.fillWidth: true
|
||||||
|
from: 0.01
|
||||||
|
to: 500.0
|
||||||
|
value: 0.2
|
||||||
|
onValueChanged: scaleEdit.text = value.toFixed(4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
Label {
|
||||||
|
text: "Fill color"
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: fillColor
|
||||||
|
color: "#ffffff"
|
||||||
|
width: 20
|
||||||
|
height: 20
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
fillColorDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ComboBox {
|
||||||
|
id: gradientType
|
||||||
|
model: [ "NoGradient", "LinearGradient", "RadialGradient", "ConicalGradient" ]
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: "Path alpha:"
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
Slider {
|
||||||
|
id: alphaSlider
|
||||||
|
Layout.fillWidth: true
|
||||||
|
from: 0.0
|
||||||
|
to: 1.0
|
||||||
|
value: 1.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
CheckBox {
|
||||||
|
id: enableOutline
|
||||||
|
text: "Enable outline"
|
||||||
|
palette.windowText: "white"
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
opacity: enableOutline.checked ? 1 : 0
|
||||||
|
Label {
|
||||||
|
text: "Outline color:"
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: outlineColor
|
||||||
|
property color selectedColor: "#33ccbb"
|
||||||
|
color: selectedColor
|
||||||
|
width: 20
|
||||||
|
height: 20
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
outlineColorDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ComboBox {
|
||||||
|
id: outlineStyle
|
||||||
|
textRole: "text"
|
||||||
|
valueRole: "style"
|
||||||
|
model: ListModel {
|
||||||
|
ListElement {
|
||||||
|
text: "Solid line"
|
||||||
|
style: ShapePath.SolidLine
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Dash line"
|
||||||
|
style: ShapePath.DashLine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ComboBox {
|
||||||
|
id: joinStyle
|
||||||
|
textRole: "text"
|
||||||
|
valueRole: "style"
|
||||||
|
model: ListModel {
|
||||||
|
ListElement {
|
||||||
|
text: "Miter join"
|
||||||
|
style: ShapePath.MiterJoin
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Bevel join"
|
||||||
|
style: ShapePath.BevelJoin
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Round join"
|
||||||
|
style: ShapePath.RoundJoin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ComboBox {
|
||||||
|
id: capStyle
|
||||||
|
textRole: "text"
|
||||||
|
valueRole: "style"
|
||||||
|
model: ListModel {
|
||||||
|
ListElement {
|
||||||
|
text: "Square cap"
|
||||||
|
style: ShapePath.SquareCap
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Round cap"
|
||||||
|
style: ShapePath.RoundCap
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Flat cap"
|
||||||
|
style: ShapePath.FlatCap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: "Outline width"
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
Slider {
|
||||||
|
id: outlineWidth
|
||||||
|
Layout.fillWidth: true
|
||||||
|
from: 0.0
|
||||||
|
to: 30.0
|
||||||
|
value: 10.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
ColorDialog {
|
||||||
|
id: outlineColorDialog
|
||||||
|
selectedColor: outlineColor.selectedColor
|
||||||
|
onAccepted: outlineColor.selectedColor = selectedColor
|
||||||
|
}
|
||||||
|
ColorDialog {
|
||||||
|
id: fillColorDialog
|
||||||
|
selectedColor: fillColor.color
|
||||||
|
onAccepted: fillColor.color = selectedColor
|
||||||
|
}
|
||||||
|
ColorDialog {
|
||||||
|
id: painterComparisonColorDialog
|
||||||
|
selectedColor: painterComparisonColor.color
|
||||||
|
onAccepted: painterComparisonColor.color = selectedColor
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: point1
|
||||||
|
color: "red"
|
||||||
|
border.width: 1
|
||||||
|
border.color: "black"
|
||||||
|
opacity: 0.3
|
||||||
|
width: 20
|
||||||
|
height: 20
|
||||||
|
|
||||||
|
property real cx: 400
|
||||||
|
property real cy: 800
|
||||||
|
|
||||||
|
property point pt: Qt.point(cx, cy)
|
||||||
|
|
||||||
|
DragHandler {
|
||||||
|
xAxis.minimum: -controlPanel.pathMargin
|
||||||
|
yAxis.minimum: -controlPanel.pathMargin
|
||||||
|
}
|
||||||
|
onXChanged: {
|
||||||
|
cx = (x + width/2) / controlPanel.scale
|
||||||
|
controlPanel.updatePath()
|
||||||
|
}
|
||||||
|
onYChanged: {
|
||||||
|
cy = (y + height/2) / controlPanel.scale
|
||||||
|
controlPanel.updatePath()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
x = cx * controlPanel.scale - width/2
|
||||||
|
y = cy * controlPanel.scale - height/2
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: controlPanel
|
||||||
|
function onScaleChanged() {
|
||||||
|
x = cx * controlPanel.scale - width/2
|
||||||
|
y = cy * controlPanel.scale - height/2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import io.qt
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: topLevel
|
||||||
|
property alias fillColor: shapePath.fillColor
|
||||||
|
property alias strokeStyle: shapePath.strokeStyle
|
||||||
|
property alias capStyle: shapePath.capStyle
|
||||||
|
property alias strokeColor: shapePath.strokeColor
|
||||||
|
property alias strokeWidth: shapePath.strokeWidth
|
||||||
|
property alias fillRule: shapePath.fillRule
|
||||||
|
|
||||||
|
property alias startX: shapePath.startX
|
||||||
|
property alias startY: shapePath.startY
|
||||||
|
|
||||||
|
property rect boundingRect: shape.boundingRect
|
||||||
|
|
||||||
|
width: boundingRect.width
|
||||||
|
height: boundingRect.height
|
||||||
|
|
||||||
|
property vector2d startPoint: "0,0"
|
||||||
|
property list<QtObject> delegate
|
||||||
|
|
||||||
|
LinearGradient {
|
||||||
|
id: linearGradient
|
||||||
|
x1: shape.boundingRect.left
|
||||||
|
y1: shape.boundingRect.top
|
||||||
|
x2: shape.boundingRect.right
|
||||||
|
y2: shape.boundingRect.bottom
|
||||||
|
GradientStop { position: 0; color: fillColor }
|
||||||
|
GradientStop { position: 1; color: Qt.rgba(1 - fillColor.r, 1 - fillColor.g, 1 - fillColor.b, 1) }
|
||||||
|
}
|
||||||
|
|
||||||
|
RadialGradient {
|
||||||
|
id: radialGradient
|
||||||
|
centerX: 0.5 * (shape.boundingRect.right + shape.boundingRect.left)
|
||||||
|
centerY: 0.5 * (shape.boundingRect.top + shape.boundingRect.bottom)
|
||||||
|
focalX: centerX
|
||||||
|
focalY: centerY
|
||||||
|
centerRadius: 0.5 * (shape.boundingRect.right - shape.boundingRect.left)
|
||||||
|
focalRadius: 0.1
|
||||||
|
GradientStop { position: 0.0; color: fillColor }
|
||||||
|
GradientStop { position: 1.0; color: Qt.rgba(1 - fillColor.r, 1 - fillColor.g, 1 - fillColor.b, 1) }
|
||||||
|
}
|
||||||
|
|
||||||
|
ConicalGradient {
|
||||||
|
id: conicalGradient
|
||||||
|
centerX: 0.5 * (shape.boundingRect.right + shape.boundingRect.left)
|
||||||
|
centerY: 0.5 * (shape.boundingRect.top + shape.boundingRect.bottom)
|
||||||
|
GradientStop { position: 0.0; color: fillColor }
|
||||||
|
GradientStop { position: 0.5; color: Qt.rgba(1 - fillColor.r, 1 - fillColor.g, 1 - fillColor.b, 1) }
|
||||||
|
GradientStop { position: 1.0; color: fillColor }
|
||||||
|
}
|
||||||
|
|
||||||
|
property var gradients: [ null, linearGradient, radialGradient, conicalGradient ]
|
||||||
|
|
||||||
|
Shape {
|
||||||
|
id: shape
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
preferredRendererType: controlPanel.preferCurve ? Shape.CurveRenderer : Shape.UnknownRenderer
|
||||||
|
onRendererTypeChanged: {
|
||||||
|
controlPanel.rendererName = rendererType == Shape.SoftwareRenderer ? "Software" :
|
||||||
|
rendererType == Shape.GeometryRenderer ? "Geometry" :
|
||||||
|
rendererType == Shape.CurveRenderer ? "Curve" : "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
transform: [
|
||||||
|
Scale {
|
||||||
|
xScale: controlPanel.scale
|
||||||
|
yScale: controlPanel.scale
|
||||||
|
origin.x: shape.implicitWidth / 2
|
||||||
|
origin.y: shape.implicitHeight / 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
ShapePath {
|
||||||
|
id: shapePath
|
||||||
|
fillRule: ShapePath.WindingFill
|
||||||
|
fillGradient: gradients[controlPanel.gradientType]
|
||||||
|
strokeColor: controlPanel.outlineColor
|
||||||
|
fillColor: controlPanel.fillColor
|
||||||
|
strokeWidth: controlPanel.outlineWidth
|
||||||
|
strokeStyle: controlPanel.outlineStyle
|
||||||
|
joinStyle: controlPanel.joinStyle
|
||||||
|
capStyle: controlPanel.capStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: topLevel.delegate
|
||||||
|
onModelChanged: {
|
||||||
|
shapePath.pathElements = []
|
||||||
|
for (var i = 0; i < model.length; ++i)
|
||||||
|
shapePath.pathElements.push(model[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: controlPanel
|
||||||
|
function onPathChanged() {
|
||||||
|
debugPaintPath.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugPaintItem {
|
||||||
|
id: debugPaintPath
|
||||||
|
shape: shapePath
|
||||||
|
visible: controlPanel.painterComparison > 0
|
||||||
|
color: controlPanel.painterComparisonColor
|
||||||
|
opacity: controlPanel.painterComparisonAlpha
|
||||||
|
z: controlPanel.painterComparison > 1 ? -1 : 0
|
||||||
|
pathScale: controlPanel.scale
|
||||||
|
fillRule: topLevel.fillRule
|
||||||
|
strokeStyle: topLevel.strokeStyle
|
||||||
|
strokeColor: controlPanel.outlineEnabled ? Qt.rgba(1 - color.r, 1 - color.g, 1 - color.b, 1) : "transparent"
|
||||||
|
capStyle: topLevel.capStyle
|
||||||
|
joinStyle: controlPanel.joinStyle
|
||||||
|
strokeWidth: topLevel.strokeWidth
|
||||||
|
|
||||||
|
width: visible ? (shape.boundingRect.width + shape.boundingRect.x) * controlPanel.scale : 1
|
||||||
|
height: visible ? (shape.boundingRect.height + shape.boundingRect.y) * controlPanel.scale : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugVisualizationController {
|
||||||
|
showCurves: controlPanel.debugCurves
|
||||||
|
showWireframe: controlPanel.debugWireframe
|
||||||
|
onSettingsChanged: { shapePath.changed() }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
fillRule: ShapePath.OddEvenFill
|
||||||
|
delegate: [
|
||||||
|
PathMove { x: start.cx; y: start.cy},
|
||||||
|
PathCubic { x: end.cx; y: end.cy;
|
||||||
|
control1X: control1.cx; control1Y: control1.cy
|
||||||
|
control2X: control2.cx; control2Y: control2.cy },
|
||||||
|
PathMove { x: start2.cx; y: start2.cy },
|
||||||
|
PathCubic { x: end2.cx; y: end2.cy;
|
||||||
|
control1X: control21.cx; control1Y: control21.cy
|
||||||
|
control2X: control22.cx; control2Y: control22.cy },
|
||||||
|
PathLine { x: lineEnd.cx; y: lineEnd.cy }
|
||||||
|
]
|
||||||
|
|
||||||
|
// Cubic path 1
|
||||||
|
ControlPoint {
|
||||||
|
id: start
|
||||||
|
cx: 200
|
||||||
|
cy: 400
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: control1
|
||||||
|
color: "blue"
|
||||||
|
cx: 800
|
||||||
|
cy: 0
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: control2
|
||||||
|
color: "blue"
|
||||||
|
cx: 800
|
||||||
|
cy: 1000
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: end
|
||||||
|
cx: 200
|
||||||
|
cy: 600
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cubic path 2
|
||||||
|
ControlPoint {
|
||||||
|
id: start2
|
||||||
|
cx: 2200
|
||||||
|
cy: 200
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: control21
|
||||||
|
color: "blue"
|
||||||
|
cx: 1200
|
||||||
|
cy: 600
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: control22
|
||||||
|
color: "blue"
|
||||||
|
cx: 3200
|
||||||
|
cy: 1000
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: end2
|
||||||
|
cx: 2200
|
||||||
|
cy: 1400
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: lineEnd
|
||||||
|
cx: 1200
|
||||||
|
cy: 200
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
1. FONTLOG for Graziano
|
||||||
|
|
||||||
|
This file provides detailed information on the Graziano
|
||||||
|
Font Software. This information should be distributed along with
|
||||||
|
the Graziano font and any derivative works.
|
||||||
|
|
||||||
|
2. Basic Font Information
|
||||||
|
|
||||||
|
A font based on my left-handed handwriting.
|
||||||
|
To take notes with Block and lowercase letters on plain
|
||||||
|
white paper without any guideline (with a large-tipped pen)
|
||||||
|
is a good training ground for writing.
|
||||||
|
|
||||||
|
3. ChangeLog
|
||||||
|
|
||||||
|
28 May 2011 (Graziano Capelli) Graziano version 1.0.
|
||||||
|
- Initial release
|
||||||
|
|
||||||
|
4 Acknowledgements
|
||||||
|
|
||||||
|
None yet. Feature requests, bug reports and contributions should be
|
||||||
|
sent to Graziano Capelli (air at shweb dot it; femtosoft at libero dot it)
|
Binary file not shown.
|
@ -0,0 +1,534 @@
|
||||||
|
OFL FAQ - Frequently Asked Questions about the SIL Open Font License (OFL)
|
||||||
|
Version 1.1-update1 - 31 March 2009
|
||||||
|
(See http://scripts.sil.org/OFL for updates)
|
||||||
|
|
||||||
|
|
||||||
|
1 ABOUT USING AND DISTRIBUTING FONTS LICENSED UNDER THE OFL
|
||||||
|
|
||||||
|
1.1 Can I use the fonts in any publication, even embedded in the file?
|
||||||
|
Yes. You may use them like most other fonts, but unlike some fonts you may
|
||||||
|
include an embedded subset of the fonts in your document. Such use does not
|
||||||
|
require you to include this license or other files (listed in OFL condition 2),
|
||||||
|
nor does it require any type of acknowledgement within the publication. Some
|
||||||
|
mention of the font name within the publication information (such as in a
|
||||||
|
colophon) is usually appreciated. If you wish to include the complete font as a
|
||||||
|
separate file, you should distribute the full font package, including all
|
||||||
|
existing acknowledgements, and comply with the OFL conditions. Of course,
|
||||||
|
referencing or embedding an OFL font in any document does not change the
|
||||||
|
license of the document itself. The requirement for fonts to remain under the
|
||||||
|
OFL does not apply to any document created using the fonts and their
|
||||||
|
derivatives. Similarly, creating any kind of graphic using a font under OFL
|
||||||
|
does not make the resulting artwork subject to the OFL.
|
||||||
|
|
||||||
|
1.2 Can I make web pages using these fonts?
|
||||||
|
Yes! Go ahead! Using CSS (Cascading Style Sheets) is recommended. Direct usage
|
||||||
|
of fonts retrieved from a remote server - also referred to as font linking -
|
||||||
|
using cross-platform open standards like @font-face is encouraged. This is
|
||||||
|
considered to be use and distribution for which the OFL explicitly grants
|
||||||
|
permission. The font file itself is not embedded in the webpage but referenced
|
||||||
|
through a web address (i.e. a URI regardless of file format or access protocol)
|
||||||
|
which will cause the browser to retrieve and use the corresponding font to
|
||||||
|
render the webpage. This usage scenario is different from font embedding within
|
||||||
|
a document (i.e. a PDF) where the font or some of its elements become part of
|
||||||
|
the document. Note that embedding in a document is also permitted by the
|
||||||
|
license as indicated in 1.1. (See 1.10 for details related to URL-based access
|
||||||
|
restrictions methods or DRM mechanisms).
|
||||||
|
|
||||||
|
1.3 Can I make the fonts available to others from my web site?
|
||||||
|
Yes, as long as you meet the conditions of the license (do not sell by itself,
|
||||||
|
include the necessary files, include the necessary copyright and license
|
||||||
|
information, rename Modified Versions, do not abuse the Author(s)' name(s) and
|
||||||
|
do not sublicense). In the case where you are hosting fonts to be served on the
|
||||||
|
web, make sure the file contains the needed copyright notice(s) and licensing
|
||||||
|
information in its metadata. Please double-check the accuracy of every field to
|
||||||
|
prevent contradictory information. If you are making the font available for use
|
||||||
|
via the @font-face open standard, putting this information in the standard font
|
||||||
|
metadata fields is sufficient. Other font formats, including EOT and proposed
|
||||||
|
superior alternatives, already provide fields for this information.
|
||||||
|
|
||||||
|
1.4 Can the fonts be included with Free/Libre and Open Source Software
|
||||||
|
collections such as GNU/Linux and BSD distributions?
|
||||||
|
Yes! Fonts licensed under the OFL can be freely aggregated with software under
|
||||||
|
FLOSS (Free/Libre and Open Source Software) licenses. Since fonts are much more
|
||||||
|
useful aggregated to than merged with existing software, possible
|
||||||
|
incompatibility with existing software licenses is not a problem. You can also
|
||||||
|
repackage the fonts and the accompanying components in a .rpm or .deb package
|
||||||
|
and include them in distro CD/DVDs and online repositories.
|
||||||
|
|
||||||
|
1.5 I want to distribute the fonts with my program. Does this mean my program
|
||||||
|
also has to be free/libre and open source software?
|
||||||
|
No. Only the portions based on the Font Software are required to be released
|
||||||
|
under the OFL. The intent of the license is to allow aggregation or bundling
|
||||||
|
with software under restricted licensing as well.
|
||||||
|
|
||||||
|
1.6 Can I include the fonts on a CD of freeware or commercial fonts?
|
||||||
|
Yes, as long some other font or software is also on the disk, so the OFL font
|
||||||
|
is not sold by itself.
|
||||||
|
|
||||||
|
1.7 Can I sell a software package that includes these fonts?
|
||||||
|
Yes, you can do this with both the Original Version and a Modified Version.
|
||||||
|
Examples of bundling made possible by the OFL would include: word processors,
|
||||||
|
design and publishing applications, training and educational software,
|
||||||
|
edutainment software, etc.
|
||||||
|
|
||||||
|
1.8 Why won't the OFL let me sell the fonts alone?
|
||||||
|
The intent is to keep people from making money by simply redistributing the
|
||||||
|
fonts. The only people who ought to profit directly from the fonts should be
|
||||||
|
the original authors, and those authors have kindly given up potential direct
|
||||||
|
income to distribute their fonts under the OFL. Please honor and respect their
|
||||||
|
contribution!
|
||||||
|
|
||||||
|
1.9 I've come across a font released under the OFL. How can I easily get more
|
||||||
|
information about the Original Version? How can I know where it stands compared
|
||||||
|
to the Original Version or other Modified Versions?
|
||||||
|
Consult the copyright statement(s) in the license for ways to contact the
|
||||||
|
original authors. Consult the FONTLOG for information on how the font differs
|
||||||
|
from the Original Version, and get in touch with the various contributors via
|
||||||
|
the information in the acknowledgment section. Please consider using the
|
||||||
|
Original Versions of the fonts whenever possible.
|
||||||
|
|
||||||
|
1.10 What do you mean in condition 4? Can you provide examples of abusive
|
||||||
|
promotion / endorsement / advertisement vs. normal acknowledgement?
|
||||||
|
The intent is that the goodwill and reputation of the author(s) should not be
|
||||||
|
used in a way that makes it sound like the original author(s) endorse or
|
||||||
|
approve of a specific Modified Version or software bundle. For example, it
|
||||||
|
would not be right to advertise a word processor by naming the author(s) in a
|
||||||
|
listing of software features, or to promote a Modified Version on a web site by
|
||||||
|
saying "designed by ...". However, it would be appropriate to acknowledge the
|
||||||
|
author(s) if your software package has a list of people who deserve thanks. We
|
||||||
|
realize that this can seem to be a gray area, but the standard used to judge an
|
||||||
|
acknowledgement is that if the acknowledgement benefits the author(s) it is
|
||||||
|
allowed, but if it primarily benefits other parties, or could reflect poorly on
|
||||||
|
the author(s), then it is not.
|
||||||
|
|
||||||
|
1.11 Can Font Software released under the OFL be subject to URL-based access
|
||||||
|
restrictions methods or DRM mechanisms?
|
||||||
|
Yes, but these issues are out-of-scope for the OFL. The license itself neither
|
||||||
|
encourages their use nor prohibits them since such mechanisms are not
|
||||||
|
implemented in the components of the Font Software but through external
|
||||||
|
software. Such restrictions are put in place for many different purposes
|
||||||
|
corresponding to various usage scenarios. One common example is to limit
|
||||||
|
potentially dangerous cross-site scripting attacks. However, in the spirit of
|
||||||
|
libre/open fonts and unrestricted writing systems, we strongly encourage open
|
||||||
|
sharing and reuse of OFL fonts, and the establishment of an environment where
|
||||||
|
such restrictions are unnecessary. Note that whether you wish to use such
|
||||||
|
mechanisms or you prefer not to, you must still abide by the rules set forth by
|
||||||
|
the OFL when using fonts released by their authors under this license.
|
||||||
|
Derivative fonts must be licensed under the OFL, even if they are part of a
|
||||||
|
service for which you charge fees and/or for which access to source code is
|
||||||
|
restricted. You may not sell the fonts on their own - they must be part of a
|
||||||
|
larger software package or bundle. For example, even if the OFL font is
|
||||||
|
distributed in a software package or via an online service using a DRM
|
||||||
|
mechanism, the user would still have the right to extract that font, use,
|
||||||
|
study, modify and redistribute it under the OFL.
|
||||||
|
|
||||||
|
1.12 What about distributing fonts with a document? Within a compressed folder
|
||||||
|
structure like an OpenDocument file (.odt) for example? Is it redistribution,
|
||||||
|
bundling or embedding?
|
||||||
|
The vast majority of the time, documents circulated in electronic form
|
||||||
|
reference a font name which will match the corresponding font on the target
|
||||||
|
system but do not carry the font within themselves. There may, however, be some
|
||||||
|
cases where you need to bundle a font with the document. Certain document
|
||||||
|
formats may allow the inclusion of an unmodified font within their file
|
||||||
|
structure which consists of a compressed folder containing the various
|
||||||
|
resources forming the document (such as pictures and thumbnails). Including
|
||||||
|
fonts within such a structure is understood as being different from embedding
|
||||||
|
but rather similar to bundling (or mere aggregation) for which the licensing
|
||||||
|
makes explicit provision. In this case the font is conveyed unchanged whereas
|
||||||
|
embedding a font transforms it from the original format. The OFL does not allow
|
||||||
|
anyone to extract the font from such a structure to then redistribute it under
|
||||||
|
another license. The explicit permission to redistribute and embed does not
|
||||||
|
cancel the requirement for the Font Software to remain under the license chosen
|
||||||
|
by its Author(s).
|
||||||
|
|
||||||
|
1.13 If OFL fonts are extracted from a document in which they are embedded
|
||||||
|
(such as a PDF file), what can be done with them? Is this a risk to Author(s)?
|
||||||
|
The few utilities that can extract fonts embedded in a PDF will only output
|
||||||
|
limited amounts of outlines - not a complete font. To create a working font
|
||||||
|
from this method is much more difficult than finding the source of the original
|
||||||
|
OFL font. So there is little chance that an OFL font would be extracted and
|
||||||
|
redistributed inappropriately through this method. Even so, copyright laws
|
||||||
|
address any misrepresentation of authorship. All Font Software released under
|
||||||
|
the OFL and marked as such by the Author(s) is intended to remain under this
|
||||||
|
license regardless of the distribution method, and cannot be redistributed
|
||||||
|
under any other license. We strongly discourage any font extraction - we
|
||||||
|
recommend directly using the font sources instead - but if you extract font
|
||||||
|
outlines from a document please be considerate, use your common sense and
|
||||||
|
respect the work of the Author(s) and the licensing model.
|
||||||
|
|
||||||
|
1.14 What about sharing OFL fonts with friends on a CD, DVD or USB stick?
|
||||||
|
You are very welcome to share open fonts with friends, family and colleagues on
|
||||||
|
such removable media. Please make sure that you share and share-alike as much
|
||||||
|
as possible from what the Author(s) released and that you don't strip away
|
||||||
|
useful information which may not be present in the binary font files
|
||||||
|
themselves. Just remember that in the case where you sell the font, it has to
|
||||||
|
come bundled with software.
|
||||||
|
|
||||||
|
|
||||||
|
2 ABOUT MODIFYING OFL LICENSED FONTS
|
||||||
|
|
||||||
|
2.1 Can I change the fonts? Are there any limitations to what things I can and
|
||||||
|
cannot change?
|
||||||
|
You are allowed to change anything, as long as such changes do not violate the
|
||||||
|
terms of the license. In other words, you are not allowed to remove the
|
||||||
|
copyright statement(s) from the font, but you could add additional information
|
||||||
|
into it that covers your contribution.
|
||||||
|
|
||||||
|
2.2 I have a font that needs a few extra glyphs - can I take them from an OFL
|
||||||
|
licensed font and copy them into mine?
|
||||||
|
Yes, but if you distribute that font to others it must be under the OFL, and
|
||||||
|
include the information mentioned in condition 2 of the license.
|
||||||
|
|
||||||
|
2.3 Can I charge people for my additional work? In other words, if I add a
|
||||||
|
bunch of special glyphs and/or OpenType/Graphite code, can I sell the enhanced
|
||||||
|
font?
|
||||||
|
Not by itself. Derivative fonts must be released under the OFL and cannot be
|
||||||
|
sold by themselves. It is permitted, however, to include them in a larger
|
||||||
|
software package (such as text editors, office suites or operating systems),
|
||||||
|
even if the larger package is sold. In that case, you are strongly encouraged,
|
||||||
|
but not required, to also make that derived font easily and freely available
|
||||||
|
outside of the larger package.
|
||||||
|
|
||||||
|
2.4 Can I pay someone to enhance the fonts for my use and distribution?
|
||||||
|
Yes. This is a good way to fund the further development of the fonts. Keep in
|
||||||
|
mind, however, that if the font is distributed to others it must be under the
|
||||||
|
OFL. You won't be able to recover your investment by exclusively selling the
|
||||||
|
font, but you will be making a valuable contribution to the community. Please
|
||||||
|
remember how you have benefitted from the contributions of others.
|
||||||
|
|
||||||
|
2.5 I need to make substantial revisions to the font to make it work with my
|
||||||
|
program. It will be a lot of work, and a big investment, and I want to be sure
|
||||||
|
that it can only be distributed with my program. Can I restrict its use?
|
||||||
|
No. If you redistribute a Modified Version of the font it must be under the
|
||||||
|
OFL. You may not restrict it in any way. This is intended to ensure that all
|
||||||
|
released improvements to the fonts become available to everyone. But you will
|
||||||
|
likely get an edge over competitors by being the first to distribute a bundle
|
||||||
|
with the enhancements. Again, please remember how you have benefitted from the
|
||||||
|
contributions of others.
|
||||||
|
|
||||||
|
2.6 Do I have to make any derivative fonts (including extended source files,
|
||||||
|
build scripts, documentation, etc.) publicly available?
|
||||||
|
No, but please do share your improvements with others. You may find that you
|
||||||
|
receive more than what you gave in return.
|
||||||
|
|
||||||
|
2.7 Why can't I use the Reserved Font Name(s) in my derivative font names? I'd
|
||||||
|
like people to know where the design came from.
|
||||||
|
The best way to acknowledge the source of the design is to thank the original
|
||||||
|
authors and any other contributors in the files that are distributed with your
|
||||||
|
revised font (although no acknowledgement is required). The FONTLOG is a
|
||||||
|
natural place to do this. Reserved Font Name(s) ensure that the only fonts that
|
||||||
|
have the original names are the unmodified Original Versions. This allows
|
||||||
|
designers to maintain artistic integrity while allowing collaboration to
|
||||||
|
happen. It eliminates potential confusion and name conflicts. When choosing a
|
||||||
|
name be creative and avoid names that reuse almost all the same letters in the
|
||||||
|
same order or sound like the original. Keep in mind that the Copyright
|
||||||
|
Holder(s) can allow a specific trusted partner to use Reserved Font Name(s)
|
||||||
|
through a separate written agreement.
|
||||||
|
|
||||||
|
2.8 What do you mean by "primary name as presented to the user"? Are you
|
||||||
|
referring to the font menu name?
|
||||||
|
Yes, the requirement to change the visible name used to differentiate the font
|
||||||
|
from others applies to the font menu name and other mechanisms to specify a
|
||||||
|
font in a document. It would be fine, for example, to keep a text reference to
|
||||||
|
the original fonts in the description field, in your modified source file or in
|
||||||
|
documentation provided alongside your derivative as long as no one could be
|
||||||
|
confused that your modified source is the original. But you cannot use the
|
||||||
|
Reserved Font Names in any way to identify the font to the user (unless the
|
||||||
|
Copyright Holder(s) allow(s) it through a separate agreement; see section 2.7).
|
||||||
|
Users who install derivatives ("Modified Versions") on their systems should not
|
||||||
|
see any of the original names ("Reserved Font Names") in their font menus, for
|
||||||
|
example. Again, this is to ensure that users are not confused and do not
|
||||||
|
mistake a font for another and so expect features only another derivative or
|
||||||
|
the Original Version can actually offer. Ultimately, creating name conflicts
|
||||||
|
will cause many problems for the users as well as for the designer of both the
|
||||||
|
Original and Modified versions, so please think ahead and find a good name for
|
||||||
|
your own derivative. Font substitution systems like fontconfig, or
|
||||||
|
application-level font fallback configuration within OpenOffice.org or Scribus,
|
||||||
|
will also get very confused if the name of the font they are configured to
|
||||||
|
substitute to actually refers to another physical font on the user's hard
|
||||||
|
drive. It will help everyone if Original Versions and Modified Versions can
|
||||||
|
easily be distinguished from one another and from other derivatives. The
|
||||||
|
substitution mechanism itself is outside the scope of the license. Users can
|
||||||
|
always manually change a font reference in a document or set up some kind of
|
||||||
|
substitution at a higher level but at the lower level the fonts themselves have
|
||||||
|
to respect the Reserved Font Name(s) requirement to prevent ambiguity. If a
|
||||||
|
substitution is currently active the user should be aware of it.
|
||||||
|
|
||||||
|
2.9 Am I not allowed to use any part of the Reserved Font Names?
|
||||||
|
You may not use the words of the font names, but you would be allowed to use
|
||||||
|
parts of words, as long as you do not use any word from the Reserved Font Names
|
||||||
|
entirely. We do not recommend using parts of words because of potential
|
||||||
|
confusion, but it is allowed. For example, if "Foobar" was a Reserved Font
|
||||||
|
Name, you would be allowed to use "Foo" or "bar", although we would not
|
||||||
|
recommend it. Such an unfortunate choice would confuse the users of your fonts
|
||||||
|
as well as make it harder for other designers to contribute.
|
||||||
|
|
||||||
|
2.10 So what should I, as an author, identify as Reserved Font Names?
|
||||||
|
Original authors are encouraged to name their fonts using clear, distinct
|
||||||
|
names, and only declare the unique parts of the name as Reserved Font Names.
|
||||||
|
For example, the author of a font called "Foobar Sans" would declare "Foobar"
|
||||||
|
as a Reserved Font Name, but not "Sans", as that is a common typographical
|
||||||
|
term, and may be a useful word to use in a derivative font name. Reserved Font
|
||||||
|
Names should also be single words. A font called "Flowing River" should have
|
||||||
|
Reserved Font Names "Flowing" and "River", not "Flowing River".
|
||||||
|
|
||||||
|
2.11 Do I, as an author, have to identify any Reserved Font Names?
|
||||||
|
No, but we strongly encourage you to do so. This is to avoid confusion between
|
||||||
|
your work and Modified versions. You may, however, give certain trusted parties
|
||||||
|
the right to use any of your Reserved Font Names through separate written
|
||||||
|
agreements. For example, even if "Foobar" is a RFN, you could write up an
|
||||||
|
agreement to give company "XYZ" the right to distribute a modified version with
|
||||||
|
a name that includes "Foobar". This allows for freedom without confusion.
|
||||||
|
|
||||||
|
2.12 Are any names (such as the main font name) reserved by default?
|
||||||
|
No. That is a change to the license as of version 1.1. If you want any names to
|
||||||
|
be Reserved Font Names, they must be specified after the copyright statement(s).
|
||||||
|
|
||||||
|
2.13 What is this FONTLOG thing exactly?
|
||||||
|
It has three purposes: 1) to provide basic information on the font to users and
|
||||||
|
other developers, 2) to document changes that have been made to the font or
|
||||||
|
accompanying files, either by the original authors or others, and 3) to provide
|
||||||
|
a place to acknowledge the authors and other contributors. Please use it! See
|
||||||
|
below for details on how changes should be noted.
|
||||||
|
|
||||||
|
2.14 Am I required to update the FONTLOG?
|
||||||
|
No, but users, designers and other developers might get very frustrated at you
|
||||||
|
if you don't! People need to know how derivative fonts differ from the
|
||||||
|
original, and how to take advantage of the changes, or build on them.
|
||||||
|
|
||||||
|
|
||||||
|
3 ABOUT THE FONTLOG
|
||||||
|
|
||||||
|
The FONTLOG can take a variety of formats, but should include these four
|
||||||
|
sections:
|
||||||
|
|
||||||
|
3.1 FONTLOG for <FontFamilyName>
|
||||||
|
This file provides detailed information on the <FontFamilyName> Font Software.
|
||||||
|
This information should be distributed along with the <FontFamilyName> fonts
|
||||||
|
and any derivative works.
|
||||||
|
|
||||||
|
3.2 Basic Font Information
|
||||||
|
(Here is where you would describe the purpose and brief specifications for the
|
||||||
|
font project, and where users can find more detailed documentation. It can also
|
||||||
|
include references to how changes can be contributed back to the Original
|
||||||
|
Version. You may also wish to include a short guide to the design, or a
|
||||||
|
reference to such a document.)
|
||||||
|
|
||||||
|
3.3 ChangeLog
|
||||||
|
(This should list both major and minor changes, most recent first. Here are
|
||||||
|
some examples:)
|
||||||
|
|
||||||
|
7 February 2007 (Pat Johnson) <NewFontFamilyName> Version 1.3
|
||||||
|
- Added Greek and Cyrillic glyphs
|
||||||
|
- Released as "<NewFontFamilyName>"
|
||||||
|
|
||||||
|
7 March 2006 (Fred Foobar) <NewFontFamilyName> Version 1.2
|
||||||
|
- Tweaked contextual behaviours
|
||||||
|
- Released as "<NewFontFamilyName>"
|
||||||
|
|
||||||
|
1 Feb 2005 (Jane Doe) <NewFontFamilyName> Version 1.1
|
||||||
|
- Improved build script performance and verbosity
|
||||||
|
- Extended the smart code documentation
|
||||||
|
- Corrected minor typos in the documentation
|
||||||
|
- Fixed position of combining inverted breve below (U+032F)
|
||||||
|
- Added OpenType/Graphite smart code for Armenian
|
||||||
|
- Added Armenian glyphs (U+0531 -> U+0587)
|
||||||
|
- Released as "<NewFontFamilyName>"
|
||||||
|
|
||||||
|
1 Jan 2005 (Joe Smith) <FontFamilyName> Version 1.0
|
||||||
|
- Initial release of font "<FontFamilyName>"
|
||||||
|
|
||||||
|
3.4 Acknowledgements
|
||||||
|
(Here is where contributors can be acknowledged.
|
||||||
|
|
||||||
|
If you make modifications be sure to add your name (N), email (E), web-address
|
||||||
|
(W) and description (D). This list is sorted by last name in alphabetical
|
||||||
|
order.)
|
||||||
|
|
||||||
|
N: Jane Doe
|
||||||
|
E: jane@university.edu
|
||||||
|
W: http://art.university.edu/projects/fonts
|
||||||
|
D: Contributor - Armenian glyphs and code
|
||||||
|
|
||||||
|
N: Fred Foobar
|
||||||
|
E: fred@foobar.org
|
||||||
|
W: http://foobar.org
|
||||||
|
D: Contributor - misc Graphite fixes
|
||||||
|
|
||||||
|
N: Pat Johnson
|
||||||
|
E: pat@fontstudio.org
|
||||||
|
W: http://pat.fontstudio.org
|
||||||
|
D: Designer - Greek & Cyrillic glyphs based on Roman design
|
||||||
|
|
||||||
|
N: Tom Parker
|
||||||
|
E: tom@company.com
|
||||||
|
W: http://www.company.com/tom/projects/fonts
|
||||||
|
D: Engineer - original smart font code
|
||||||
|
|
||||||
|
N: Joe Smith
|
||||||
|
E: joe@fontstudio.org
|
||||||
|
W: http://joe.fontstudio.org
|
||||||
|
D: Designer - original Roman glyphs
|
||||||
|
|
||||||
|
(Original authors can also include information here about their organization.)
|
||||||
|
|
||||||
|
|
||||||
|
4 ABOUT MAKING CONTRIBUTIONS
|
||||||
|
|
||||||
|
4.1 Why should I contribute my changes back to the original authors?
|
||||||
|
It would benefit many people if you contributed back to what you've received.
|
||||||
|
Providing your contributions and improvements to the fonts and other components
|
||||||
|
(data files, source code, build scripts, documentation, etc.) could be a
|
||||||
|
tremendous help and would encourage others to contribute as well and 'give
|
||||||
|
back', which means you will have an opportunity to benefit from other people's
|
||||||
|
contributions as well. Sometimes maintaining your own separate version takes
|
||||||
|
more effort than merging back with the original. Be aware that any
|
||||||
|
contributions, however, must be either your own original creation or work that
|
||||||
|
you own, and you may be asked to affirm that clearly when you contribute.
|
||||||
|
|
||||||
|
4.2 I've made some very nice improvements to the font, will you consider
|
||||||
|
adopting them and putting them into future Original Versions?
|
||||||
|
Most authors would be very happy to receive such contributions. Keep in mind
|
||||||
|
that it is unlikely that they would want to incorporate major changes that
|
||||||
|
would require additional work on their end. Any contributions would likely need
|
||||||
|
to be made for all the fonts in a family and match the overall design and
|
||||||
|
style. Authors are encouraged to include a guide to the design with the fonts.
|
||||||
|
It would also help to have contributions submitted as patches or clearly marked
|
||||||
|
changes (the use of smart source revision control systems like subversion, svk,
|
||||||
|
mercurial, git or bzr is a good idea). Examples of useful contributions are bug
|
||||||
|
fixes, additional glyphs, stylistic alternates (and the smart font code to
|
||||||
|
access them) or improved hinting.
|
||||||
|
|
||||||
|
4.3 How can I financially support the development of OFL fonts?
|
||||||
|
It is likely that most authors of OFL fonts would accept financial
|
||||||
|
contributions - contact them for instructions on how to do this. Such
|
||||||
|
contributions would support future development. You can also pay for others to
|
||||||
|
enhance the fonts and contribute the results back to the original authors for
|
||||||
|
inclusion in the Original Version.
|
||||||
|
|
||||||
|
|
||||||
|
5 ABOUT THE LICENSE
|
||||||
|
|
||||||
|
5.1 I see that this is version 1.1 of the license. Will there be later changes?
|
||||||
|
Version 1.1 is the first minor revision of the OFL. We are confident that
|
||||||
|
version 1.1 will meet most needs, but are open to future improvements. Any
|
||||||
|
revisions would be for future font releases, and previously existing licenses
|
||||||
|
would remain in effect. No retroactive changes are possible, although the
|
||||||
|
Copyright Holder(s) can re-release the font under a revised OFL. All versions
|
||||||
|
will be available on our web site: http://scripts.sil.org/OFL.
|
||||||
|
|
||||||
|
5.2 Can I use the SIL Open Font License for my own fonts?
|
||||||
|
Yes! We heartily encourage anyone to use the OFL to distribute their own
|
||||||
|
original fonts. It is a carefully constructed license that allows great freedom
|
||||||
|
along with enough artistic integrity protection for the work of the authors as
|
||||||
|
well as clear rules for other contributors and those who redistribute the
|
||||||
|
fonts. Some additional information about using the OFL is included at the end
|
||||||
|
of this FAQ.
|
||||||
|
|
||||||
|
5.3 Does this license restrict the rights of the Copyright Holder(s)?
|
||||||
|
No. The Copyright Holder(s) still retain(s) all the rights to their creation;
|
||||||
|
they are only releasing a portion of it for use in a specific way. For example,
|
||||||
|
the Copyright Holder(s) may choose to release a 'basic' version of their font
|
||||||
|
under the OFL, but sell a restricted 'enhanced' version. Only the Copyright
|
||||||
|
Holder(s) can do this.
|
||||||
|
|
||||||
|
5.4 Is the OFL a contract or a license?
|
||||||
|
The OFL is a license and not a contract and so does not require you to sign it
|
||||||
|
to have legal validity. By using, modifying and redistributing components under
|
||||||
|
the OFL you indicate that you accept the license.
|
||||||
|
|
||||||
|
5.5 How about translating the license and the FAQ into other languages?
|
||||||
|
SIL certainly recognises the need for people who are not familiar with English
|
||||||
|
to be able to understand the OFL and this FAQ better in their own language.
|
||||||
|
Making the license very clear and readable is a key goal of the OFL.
|
||||||
|
|
||||||
|
If you are an experienced translator, you are very welcome to help by
|
||||||
|
translating the OFL and its FAQ so that designers and users in your language
|
||||||
|
community can understand the license better. But only the original English
|
||||||
|
version of the license has legal value and has been approved by the community.
|
||||||
|
Translations do not count as legal substitutes and should only serve as a way
|
||||||
|
to explain the original license. SIL - as the author and steward of the license
|
||||||
|
for the community at large - does not approve any translation of the OFL as
|
||||||
|
legally valid because even small translation ambiguities could be abused and
|
||||||
|
create problems.
|
||||||
|
|
||||||
|
We give permission to publish unofficial translations into other languages
|
||||||
|
provided that they comply with the following guidelines:
|
||||||
|
|
||||||
|
- put the following disclaimer in both English and the target language stating
|
||||||
|
clearly that the translation is unofficial:
|
||||||
|
|
||||||
|
"This is an unofficial translation of the SIL Open Font License into $language.
|
||||||
|
It was not published by SIL International, and does not legally state the
|
||||||
|
distribution terms for fonts that use the OFL. A release under the OFL is only
|
||||||
|
valid when using the original English text.
|
||||||
|
|
||||||
|
However, we recognize that this unofficial translation will help users and
|
||||||
|
designers not familiar with English to understand the SIL OFL better and make
|
||||||
|
it easier to use and release font families under this collaborative font design
|
||||||
|
model. We encourage designers who consider releasing their creation under the
|
||||||
|
OFL to read the FAQ in their own language if it is available.
|
||||||
|
|
||||||
|
Please go to http://scripts.sil.org/OFL for the official version of the license
|
||||||
|
and the accompanying FAQ."
|
||||||
|
|
||||||
|
- keep your unofficial translation current and update it at our request if
|
||||||
|
needed, for example if there is any ambiguity which could lead to confusion.
|
||||||
|
|
||||||
|
If you start such a unofficial translation effort of the OFL and its
|
||||||
|
accompanying FAQ please let us know, thank you.
|
||||||
|
|
||||||
|
|
||||||
|
6 ABOUT SIL INTERNATIONAL
|
||||||
|
|
||||||
|
6.1 Who is SIL International and what does it do?
|
||||||
|
SIL International is a worldwide faith-based education and development
|
||||||
|
organization (NGO) that studies, documents, and assists in developing the
|
||||||
|
world's lesser-known languages through literacy, linguistics, translation, and
|
||||||
|
other academic disciplines. SIL makes its services available to all without
|
||||||
|
regard to religious belief, political ideology, gender, race, or ethnic
|
||||||
|
background. SIL's members and volunteers share a Christian commitment.
|
||||||
|
|
||||||
|
6.2 What does this have to do with font licensing?
|
||||||
|
The ability to read, write, type and publish in one's own language is one of
|
||||||
|
the most critical needs for millions of people around the world. This requires
|
||||||
|
fonts that are widely available and support lesser-known languages. SIL
|
||||||
|
develops - and encourages others to develop - a complete stack of writing
|
||||||
|
systems implementation components available under open licenses. This open
|
||||||
|
stack includes input methods, smart fonts, smart rendering libraries and smart
|
||||||
|
applications. There has been a need for a common open license that is
|
||||||
|
specifically applicable to fonts and related software (a crucial component of
|
||||||
|
this stack) so SIL developed the SIL Open Font License with the help of the
|
||||||
|
FLOSS community.
|
||||||
|
|
||||||
|
6.3 How can I contact SIL?
|
||||||
|
Our main web site is: http://www.sil.org/
|
||||||
|
Our site about complex scripts is: http://scripts.sil.org/
|
||||||
|
Information about this license (including contact email information) is at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
7 ABOUT USING THE OFL FOR YOUR ORIGINAL FONTS
|
||||||
|
|
||||||
|
If you want to release your fonts under the OFL, you only need to do the
|
||||||
|
following:
|
||||||
|
|
||||||
|
7.1 Put your copyright and reserved font names information in the beginning of
|
||||||
|
the main OFL file (simply use the dedicated placeholders).
|
||||||
|
7.2 Put your copyright and the OFL references in your various font files (such
|
||||||
|
as in the copyright, license and description fields) and in your other
|
||||||
|
components (build scripts, glyph databases, documentation, rendering samples,
|
||||||
|
etc). Accurate metadata in your font files is beneficial to you as an
|
||||||
|
increasing number of applications are exposing this information to the user.
|
||||||
|
For example, clickable links can bring users back to your website and let them
|
||||||
|
know about other work you have done or services you provide. Depending on the
|
||||||
|
format of your fonts and sources, you can use template human-readable headers
|
||||||
|
or machine-readable metadata.
|
||||||
|
7.3 Write an initial FONTLOG for your font and include it in the release
|
||||||
|
package.
|
||||||
|
7.4 Include the OFL license file in your release package.
|
||||||
|
7.5 We also highly recommend you include the relevant practical documentation
|
||||||
|
on the license by putting the OFL-FAQ in your package.
|
||||||
|
7.6 If you wish, you can use the OFL Graphics on your web page.
|
||||||
|
|
||||||
|
That's all. If you have any more questions please get in touch with us.
|
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright (c) 2011, Graziano Capelli (air@shweb.it; femtosoft@libero.it).
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@ -0,0 +1,7 @@
|
||||||
|
SVGs included:
|
||||||
|
peace_victory.svg: Public Domain by OpenClipart (https://freesvg.org/peace-sign)
|
||||||
|
hand-print.svg: Public Domain by OpenClipart (https://freesvg.org/palm-print-in-black-and-white)
|
||||||
|
1535737773.svg: Public Domain by publicdomainvectors.org (https://freesvg.org/piece-of-cake-4)
|
||||||
|
|
||||||
|
Fonts included:
|
||||||
|
Graziano.ttf: by Graziano Capelli (https://fontlibrary.org/en/font/graziano), OFL (SIL Open Font License)
|
|
@ -0,0 +1,117 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
fillRule: ShapePath.OddEvenFill
|
||||||
|
delegate: [
|
||||||
|
// A triangle
|
||||||
|
PathPolyline {
|
||||||
|
id: ppl
|
||||||
|
path: [ Qt.point(100.0, 100.0),
|
||||||
|
Qt.point(1250.0, 150.0),
|
||||||
|
Qt.point(100.0, 1000.0),
|
||||||
|
Qt.point(100, 100)
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// A very narrow shape with one convex and one concave curve
|
||||||
|
PathMove { x: 600; y: 1200},
|
||||||
|
PathQuad { x: 800; y: 1200; controlX: 700; controlY: 600 },
|
||||||
|
PathQuad { x: 600; y: 1200; controlX: 700; controlY: 700 },
|
||||||
|
|
||||||
|
// A more complex path with editable points
|
||||||
|
PathMove { x: p1.cx; y: p1.cy },
|
||||||
|
PathQuad { x: p2.cx; y: p2.cy; controlX: c1.cx; controlY: c1.cy },
|
||||||
|
PathQuad { x: p3.cx; y: p3.cy; controlX: c2.cx; controlY: c2.cy },
|
||||||
|
PathQuad { x: p4.cx; y: p4.cy; controlX: c3.cx; controlY: c3.cy },
|
||||||
|
PathLine { x: p5.cx; y: p5.cy },
|
||||||
|
PathQuad { x: p6.cx; y: p6.cy; controlX: c5.cx; controlY: c5.cy },
|
||||||
|
PathQuad { x: p7.cx; y: p7.cy; controlX: c6.cx; controlY: c6.cy },
|
||||||
|
PathQuad { x: p8.cx; y: p8.cy; controlX: c7.cx; controlY: c7.cy }
|
||||||
|
]
|
||||||
|
|
||||||
|
// Control points for the editable part:
|
||||||
|
// Curve p1-c1-p2, Curve p2-c2-p3, Curve p3-c3-p4
|
||||||
|
// Line p4-p5, Curve p5-c5-p6, Curve p6-c6-p7, Curve p7-c7-p8
|
||||||
|
|
||||||
|
ControlPoint {
|
||||||
|
id: p1
|
||||||
|
cx: 100
|
||||||
|
cy: 1000
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: c1
|
||||||
|
color: "blue"
|
||||||
|
cx: 200
|
||||||
|
cy: 1500
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: p2
|
||||||
|
cx: 700
|
||||||
|
cy: 1500
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: c2
|
||||||
|
color: "blue"
|
||||||
|
cx: 1200
|
||||||
|
cy: 1500
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: p3
|
||||||
|
cx: 1200
|
||||||
|
cy: 1000
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: c3
|
||||||
|
color: "blue"
|
||||||
|
cx: 1100
|
||||||
|
cy: 700
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: p4
|
||||||
|
cx: 800
|
||||||
|
cy: 600
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: p5
|
||||||
|
cx: 800
|
||||||
|
cy: 800
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: c5
|
||||||
|
color: "blue"
|
||||||
|
cx: 1000
|
||||||
|
cy: 600
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: p6
|
||||||
|
cx: 1000
|
||||||
|
cy: 1000
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: c6
|
||||||
|
color: "blue"
|
||||||
|
cx: 1000
|
||||||
|
cy: 1300
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: p7
|
||||||
|
cx: 700
|
||||||
|
cy: 1300
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: c7
|
||||||
|
color: "blue"
|
||||||
|
cx: 400
|
||||||
|
cy: 1300
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: p8
|
||||||
|
cx: 400
|
||||||
|
cy: 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
fillRule: ShapePath.OddEvenFill
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathPolyline {
|
||||||
|
path: [ point1.pt,
|
||||||
|
point2.pt,
|
||||||
|
point3.pt,
|
||||||
|
point4.pt,
|
||||||
|
point5.pt,
|
||||||
|
point1.pt
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
ControlPoint {
|
||||||
|
id: point1
|
||||||
|
cx: 400
|
||||||
|
cy: 900
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: point2
|
||||||
|
cx: 1500
|
||||||
|
cy: 600
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: point3
|
||||||
|
cx: 2500
|
||||||
|
cy: 1100
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: point4
|
||||||
|
cx: 3000
|
||||||
|
cy: 1100
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: point5
|
||||||
|
cx: 2000
|
||||||
|
cy: 1900
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
delegate: [
|
||||||
|
PathMove { x: p1.cx; y: p1.cy },
|
||||||
|
PathQuad { x: p2.cx; y: p2.cy; controlX: c1.cx; controlY: c1.cy },
|
||||||
|
PathQuad { x: p3.cx; y: p3.cy; controlX: c2.cx; controlY: c2.cy },
|
||||||
|
PathQuad { x: p4.cx; y: p4.cy; controlX: c3.cx; controlY: c3.cy },
|
||||||
|
//PathQuad { x: 600; y: 100; controlX: 100; controlY: 100 },
|
||||||
|
PathLine { x: p5.cx; y: p5.cy }
|
||||||
|
]
|
||||||
|
|
||||||
|
ControlPoint {
|
||||||
|
id: p1
|
||||||
|
cx: 600
|
||||||
|
cy: 100
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: c1
|
||||||
|
color: "blue"
|
||||||
|
cx: 1100
|
||||||
|
cy: 100
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: p2
|
||||||
|
cx: 1100
|
||||||
|
cy: 600
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: c2
|
||||||
|
color: "blue"
|
||||||
|
cx: 1100
|
||||||
|
cy: 1100
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: p3
|
||||||
|
cx: 600
|
||||||
|
cy: 1100
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: c3
|
||||||
|
color: "blue"
|
||||||
|
cx: 100
|
||||||
|
cy: 1100
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: p4
|
||||||
|
cx: 100
|
||||||
|
cy: 600
|
||||||
|
}
|
||||||
|
ControlPoint {
|
||||||
|
id: p5
|
||||||
|
cx: 600
|
||||||
|
cy: 330
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Dialogs
|
||||||
|
import io.qt
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: topLevel
|
||||||
|
property var boundingRect: Qt.rect(0, 0, 100, 100)
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: fileNameLabel
|
||||||
|
x: boundingRect.x
|
||||||
|
y: boundingRect.bottom * controlPanel.scale + font.pixelSize*2
|
||||||
|
text: "Filename: " + pathLoader.source
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolButton {
|
||||||
|
anchors.left: fileNameLabel.right
|
||||||
|
anchors.top: fileNameLabel.top
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
text: "..."
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
fileDialog.visible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property var children: []
|
||||||
|
SvgPathLoader {
|
||||||
|
id: pathLoader
|
||||||
|
function reload()
|
||||||
|
{
|
||||||
|
for (var j = 0; j < children.length; ++j) {
|
||||||
|
children[j].destroy()
|
||||||
|
}
|
||||||
|
children = []
|
||||||
|
|
||||||
|
let first = true
|
||||||
|
let pickOne = controlPanel.subShape
|
||||||
|
if (pickOne < 0)
|
||||||
|
console.debug("Creating " + pathLoader.paths.length + " SVG items")
|
||||||
|
else
|
||||||
|
console.log("Creating SVG item", pickOne, "out of", pathLoader.paths.length)
|
||||||
|
for (var i = 0; i < pathLoader.paths.length; ++i) {
|
||||||
|
if (pickOne >= 0 && pickOne !== i)
|
||||||
|
continue
|
||||||
|
var s = pathLoader.paths[i]
|
||||||
|
var fillColor = pathLoader.fillColors[i]
|
||||||
|
var obj = Qt.createQmlObject("import QtQuick\nimport QtQuick.Shapes\n ControlledShape { fillColor: \"" + fillColor + "\"; fillRule: ShapePath.WindingFill; delegate: [ PathSvg { path: \"" + s + "\"; } ] }", topLevel, "SvgPathComponent_" + i)
|
||||||
|
children.push(obj)
|
||||||
|
if (first) {
|
||||||
|
topLevel.boundingRect = obj.boundingRect
|
||||||
|
first = false
|
||||||
|
} else {
|
||||||
|
var minX = Math.min(topLevel.boundingRect.x, obj.boundingRect.x)
|
||||||
|
var minY = Math.min(topLevel.boundingRect.y, obj.boundingRect.y)
|
||||||
|
var maxX = Math.max(topLevel.boundingRect.x + topLevel.boundingRect.width,
|
||||||
|
obj.boundingRect.x + obj.boundingRect.width)
|
||||||
|
var maxY = Math.max(topLevel.boundingRect.y + topLevel.boundingRect.height,
|
||||||
|
obj.boundingRect.y + obj.boundingRect.height)
|
||||||
|
|
||||||
|
topLevel.boundingRect = Qt.rect(minX, minY, maxX - minX, maxY - minY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.debug("Finished SVG")
|
||||||
|
}
|
||||||
|
onPathsChanged: reload()
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
pathLoader.source = "qrc:/1535737773.svg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: controlPanel
|
||||||
|
function onSubShapeChanged() { pathLoader.reload() }
|
||||||
|
}
|
||||||
|
|
||||||
|
FileDialog {
|
||||||
|
id: fileDialog
|
||||||
|
title: "Please choose a file"
|
||||||
|
onAccepted: {
|
||||||
|
pathLoader.source = fileDialog.selectedFile
|
||||||
|
fileDialog.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Dialogs
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
fillRule: ShapePath.OddEvenFill
|
||||||
|
delegate: [
|
||||||
|
PathText {
|
||||||
|
text: "foobar"
|
||||||
|
font: fontDialog.selectedFont
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
FontDialog {
|
||||||
|
id: fontDialog
|
||||||
|
currentFont.family: "Graziano"
|
||||||
|
currentFont.pixelSize: 500
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
anchors.top: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
text: "Select font"
|
||||||
|
onClicked: fontDialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Repeater {
|
||||||
|
anchors.fill: parent
|
||||||
|
model: 2
|
||||||
|
delegate: ControlledShape {
|
||||||
|
id: delegate
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
fillColor: "transparent"
|
||||||
|
strokeColor: delegate.index === 0 ? "red" : "blue"
|
||||||
|
strokeStyle: ShapePath.DashLine
|
||||||
|
strokeWidth: 4
|
||||||
|
|
||||||
|
startX: 4
|
||||||
|
startY: 4
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathArc {
|
||||||
|
id: arc
|
||||||
|
x: 96
|
||||||
|
y: 96
|
||||||
|
radiusX: 100
|
||||||
|
radiusY: 100
|
||||||
|
direction: delegate.index === 0 ? PathArc.Clockwise : PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright (C) 2021 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Repeater {
|
||||||
|
anchors.fill: parent
|
||||||
|
model: 2
|
||||||
|
delegate: ControlledShape {
|
||||||
|
id: delegate1
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
fillColor: "transparent"
|
||||||
|
strokeColor: delegate1.index === 0 ? "red" : "blue"
|
||||||
|
strokeStyle: ShapePath.DashLine
|
||||||
|
strokeWidth: 4
|
||||||
|
|
||||||
|
width: 200
|
||||||
|
height: 200
|
||||||
|
anchors.centerIn: parent
|
||||||
|
startX: 50
|
||||||
|
startY: 100
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathArc {
|
||||||
|
x: 150
|
||||||
|
y: 100
|
||||||
|
radiusX: 50
|
||||||
|
radiusY: 20
|
||||||
|
xAxisRotation: delegate1.index === 0 ? 0 : 45
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
anchors.fill: parent
|
||||||
|
model: 2
|
||||||
|
delegate: ControlledShape {
|
||||||
|
id: delegate2
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
width: 200
|
||||||
|
height: 200
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
fillColor: "transparent"
|
||||||
|
strokeColor: delegate2.index === 0 ? "red" : "blue"
|
||||||
|
|
||||||
|
startX: 50
|
||||||
|
startY: 100
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathArc {
|
||||||
|
x: 150
|
||||||
|
y: 100
|
||||||
|
radiusX: 50
|
||||||
|
radiusY: 20
|
||||||
|
xAxisRotation: delegate2.index === 0 ? 0 : 45
|
||||||
|
direction: PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
id: capTest
|
||||||
|
strokeColor: "green"
|
||||||
|
strokeWidth: 20
|
||||||
|
fillColor: "transparent"
|
||||||
|
|
||||||
|
property int capStyleIdx: 0
|
||||||
|
readonly property variant styles: [ ShapePath.FlatCap, ShapePath.SquareCap, ShapePath.RoundCap ]
|
||||||
|
readonly property variant styleTexts: [ qsTr("FlatCap"), qsTr("SquareCap"), qsTr("RoundCap") ]
|
||||||
|
|
||||||
|
capStyle: styles[capStyleIdx]
|
||||||
|
|
||||||
|
startX: 40
|
||||||
|
startY: 30
|
||||||
|
delegate: [
|
||||||
|
PathQuad {
|
||||||
|
x: 50
|
||||||
|
y: 80
|
||||||
|
controlX: 0
|
||||||
|
controlY: 80
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
x: 150
|
||||||
|
y: 80
|
||||||
|
},
|
||||||
|
PathQuad {
|
||||||
|
x: 160
|
||||||
|
y: 30
|
||||||
|
controlX: 200
|
||||||
|
controlY: 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 1000
|
||||||
|
repeat: true
|
||||||
|
running: true
|
||||||
|
onTriggered: capTest.capStyleIdx = (capTest.capStyleIdx + 1) % capTest.styles.length
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
id: shape
|
||||||
|
|
||||||
|
strokeWidth: 4
|
||||||
|
strokeColor: "black"
|
||||||
|
|
||||||
|
startX: 50
|
||||||
|
startY: 100
|
||||||
|
delegate: [
|
||||||
|
PathCubic {
|
||||||
|
x: 150
|
||||||
|
y: 100
|
||||||
|
control1X: cp1.x
|
||||||
|
control1Y: cp1.y
|
||||||
|
control2X: cp2.x
|
||||||
|
control2Y: cp2.y
|
||||||
|
}
|
||||||
|
]
|
||||||
|
Rectangle {
|
||||||
|
id: cp1
|
||||||
|
color: "red"
|
||||||
|
width: 10
|
||||||
|
height: 10
|
||||||
|
SequentialAnimation {
|
||||||
|
loops: Animation.Infinite
|
||||||
|
running: true
|
||||||
|
NumberAnimation {
|
||||||
|
target: cp1
|
||||||
|
property: "x"
|
||||||
|
from: 0
|
||||||
|
to: flickable.width - cp1.width
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
target: cp1
|
||||||
|
property: "x"
|
||||||
|
from: flickable.width - cp1.width
|
||||||
|
to: 0
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
target: cp1
|
||||||
|
property: "y"
|
||||||
|
from: 0
|
||||||
|
to: flickable.height - cp1.height
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
target: cp1
|
||||||
|
property: "y"
|
||||||
|
from: flickable.height - cp1.height
|
||||||
|
to: 0
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: cp2
|
||||||
|
color: "blue"
|
||||||
|
width: 10
|
||||||
|
height: 10
|
||||||
|
x: flickable.width - width
|
||||||
|
SequentialAnimation {
|
||||||
|
loops: Animation.Infinite
|
||||||
|
running: true
|
||||||
|
NumberAnimation {
|
||||||
|
target: cp2
|
||||||
|
property: "y"
|
||||||
|
from: 0
|
||||||
|
to: flickable.height - cp2.height
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
target: cp2
|
||||||
|
property: "y"
|
||||||
|
from: flickable.height - cp2.height
|
||||||
|
to: 0
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
target: cp2
|
||||||
|
property: "x"
|
||||||
|
from: flickable.width - cp2.width
|
||||||
|
to: 0
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
target: cp2
|
||||||
|
property: "x"
|
||||||
|
from: 0
|
||||||
|
to: flickable.width - cp2.width
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
id: shape
|
||||||
|
anchors.fill: parent
|
||||||
|
strokeWidth: 5
|
||||||
|
strokeColor: "blue"
|
||||||
|
strokeStyle: ShapePath.DashLine
|
||||||
|
//dashPattern: [ 1, 4, 4, 4 ]
|
||||||
|
fillColor: "lightBlue"
|
||||||
|
property real xr: 70
|
||||||
|
property real yr: 30
|
||||||
|
startX: shape.width / 2 - xr
|
||||||
|
startY: shape.height / 2 - yr
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathArc {
|
||||||
|
x: shape.width / 2 + shape.xr
|
||||||
|
y: shape.height / 2 + shape.yr
|
||||||
|
radiusX: shape.xr
|
||||||
|
radiusY: shape.yr
|
||||||
|
useLargeArc: true
|
||||||
|
},
|
||||||
|
PathArc {
|
||||||
|
x: shape.width / 2 - shape.xr
|
||||||
|
y: shape.height / 2 - shape.yr
|
||||||
|
radiusX: shape.xr
|
||||||
|
radiusY: shape.yr
|
||||||
|
useLargeArc: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
#include "debugpaintitem.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPen>
|
||||||
|
|
||||||
|
DebugPaintItem::DebugPaintItem(QQuickItem *item)
|
||||||
|
: QQuickPaintedItem(item)
|
||||||
|
{
|
||||||
|
connect(this, &DebugPaintItem::shapeChanged, this, &QQuickItem::update);
|
||||||
|
connect(this, &DebugPaintItem::colorChanged, this, &QQuickItem::update);
|
||||||
|
connect(this, &DebugPaintItem::pathScaleChanged, this, &QQuickItem::update);
|
||||||
|
connect(this, &DebugPaintItem::fillRuleChanged, this, &QQuickItem::update);
|
||||||
|
connect(this, &DebugPaintItem::strokeChanged, this, &QQuickItem::update);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPaintItem::setShape(QQuickPath *p)
|
||||||
|
{
|
||||||
|
if (p == m_path)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_path = p;
|
||||||
|
emit shapeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QQuickPath *DebugPaintItem::shape() const
|
||||||
|
{
|
||||||
|
return m_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPaintItem::handlePathChanged()
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPaintItem::paint(QPainter *p)
|
||||||
|
{
|
||||||
|
if (!isVisible())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_path != nullptr) {
|
||||||
|
QPainterPath painterPath = m_path->path();
|
||||||
|
painterPath.setFillRule(m_fillRule);
|
||||||
|
|
||||||
|
p->scale(m_pathScale, m_pathScale);
|
||||||
|
p->setRenderHint(QPainter::Antialiasing);
|
||||||
|
if (m_strokeColor.alpha() > 0) {
|
||||||
|
QPen pen(m_strokeStyle);
|
||||||
|
pen.setWidthF(m_strokeWidth);
|
||||||
|
pen.setCapStyle(m_capStyle);
|
||||||
|
pen.setJoinStyle(m_joinStyle);
|
||||||
|
pen.setColor(m_strokeColor);
|
||||||
|
p->setPen(pen);
|
||||||
|
} else {
|
||||||
|
p->setPen(Qt::NoPen);
|
||||||
|
}
|
||||||
|
p->setBrush(m_color);
|
||||||
|
p->drawPath(painterPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor DebugPaintItem::color() const
|
||||||
|
{
|
||||||
|
return m_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPaintItem::setColor(const QColor &color)
|
||||||
|
{
|
||||||
|
if (m_color == color)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_color = color;
|
||||||
|
emit colorChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPaintItem::setPathScale(qreal pathScale)
|
||||||
|
{
|
||||||
|
if (qFuzzyCompare(m_pathScale, pathScale))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_pathScale = pathScale;
|
||||||
|
emit pathScaleChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal DebugPaintItem::pathScale() const
|
||||||
|
{
|
||||||
|
return m_pathScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPaintItem::setFillRule(Qt::FillRule fillRule)
|
||||||
|
{
|
||||||
|
if (m_fillRule == fillRule)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_fillRule = fillRule;
|
||||||
|
emit fillRuleChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::FillRule DebugPaintItem::fillRule() const
|
||||||
|
{
|
||||||
|
return m_fillRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPaintItem::setStrokeColor(const QColor &strokeColor)
|
||||||
|
{
|
||||||
|
if (m_strokeColor == strokeColor)
|
||||||
|
return;
|
||||||
|
m_strokeColor = strokeColor;
|
||||||
|
emit strokeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor DebugPaintItem::strokeColor() const
|
||||||
|
{
|
||||||
|
return m_strokeColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPaintItem::setStrokeStyle(Qt::PenStyle strokeStyle)
|
||||||
|
{
|
||||||
|
if (m_strokeStyle == strokeStyle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_strokeStyle = strokeStyle;
|
||||||
|
emit strokeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::PenStyle DebugPaintItem::strokeStyle() const
|
||||||
|
{
|
||||||
|
return m_strokeStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPaintItem::setJoinStyle(Qt::PenJoinStyle style)
|
||||||
|
{
|
||||||
|
if (m_joinStyle == style)
|
||||||
|
return;
|
||||||
|
m_joinStyle = style;
|
||||||
|
emit strokeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::PenJoinStyle DebugPaintItem::joinStyle() const
|
||||||
|
{
|
||||||
|
return m_joinStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPaintItem::setCapStyle(Qt::PenCapStyle style)
|
||||||
|
{
|
||||||
|
if (m_capStyle == style)
|
||||||
|
return;
|
||||||
|
m_capStyle = style;
|
||||||
|
emit strokeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::PenCapStyle DebugPaintItem::capStyle() const
|
||||||
|
{
|
||||||
|
return m_capStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPaintItem::setStrokeWidth(qreal w)
|
||||||
|
{
|
||||||
|
if (qFuzzyCompare(m_strokeWidth, w))
|
||||||
|
return;
|
||||||
|
m_strokeWidth = w;
|
||||||
|
emit strokeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal DebugPaintItem::strokeWidth() const
|
||||||
|
{
|
||||||
|
return m_strokeWidth;
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
#ifndef DEBUGPAINTITEM_H
|
||||||
|
#define DEBUGPAINTITEM_H
|
||||||
|
|
||||||
|
#include <QQuickPaintedItem>
|
||||||
|
#include <QtQuick/private/qquickpath_p.h>
|
||||||
|
|
||||||
|
class DebugPaintItem : public QQuickPaintedItem
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QQuickPath *shape READ shape WRITE setShape NOTIFY shapeChanged)
|
||||||
|
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
|
||||||
|
Q_PROPERTY(qreal pathScale READ pathScale WRITE setPathScale NOTIFY pathScaleChanged)
|
||||||
|
Q_PROPERTY(Qt::FillRule fillRule READ fillRule WRITE setFillRule NOTIFY fillRuleChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(QColor strokeColor READ strokeColor WRITE setStrokeColor NOTIFY strokeChanged)
|
||||||
|
Q_PROPERTY(Qt::PenStyle strokeStyle READ strokeStyle WRITE setStrokeStyle NOTIFY strokeChanged)
|
||||||
|
Q_PROPERTY(Qt::PenJoinStyle joinStyle READ joinStyle WRITE setJoinStyle NOTIFY strokeChanged)
|
||||||
|
Q_PROPERTY(Qt::PenCapStyle capStyle READ capStyle WRITE setCapStyle NOTIFY strokeChanged)
|
||||||
|
Q_PROPERTY(qreal strokeWidth READ strokeWidth WRITE setStrokeWidth NOTIFY strokeChanged)
|
||||||
|
public:
|
||||||
|
DebugPaintItem(QQuickItem *item = nullptr);
|
||||||
|
|
||||||
|
void setShape(QQuickPath *path);
|
||||||
|
QQuickPath *shape() const;
|
||||||
|
|
||||||
|
void setColor(const QColor &color);
|
||||||
|
QColor color() const;
|
||||||
|
|
||||||
|
void setPathScale(qreal pathScale);
|
||||||
|
qreal pathScale() const;
|
||||||
|
|
||||||
|
void setFillRule(Qt::FillRule filleRule);
|
||||||
|
Qt::FillRule fillRule() const;
|
||||||
|
|
||||||
|
QColor strokeColor() const;
|
||||||
|
void setStrokeColor(const QColor &strokeColor);
|
||||||
|
|
||||||
|
Qt::PenStyle strokeStyle() const;
|
||||||
|
void setStrokeStyle(Qt::PenStyle penStyle);
|
||||||
|
|
||||||
|
Qt::PenJoinStyle joinStyle() const;
|
||||||
|
void setJoinStyle(Qt::PenJoinStyle style);
|
||||||
|
|
||||||
|
Qt::PenCapStyle capStyle() const;
|
||||||
|
void setCapStyle(Qt::PenCapStyle style);
|
||||||
|
|
||||||
|
qreal strokeWidth() const;
|
||||||
|
void setStrokeWidth(qreal w);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void shapeChanged();
|
||||||
|
void colorChanged();
|
||||||
|
void opacityChanged();
|
||||||
|
void pathScaleChanged();
|
||||||
|
void fillRuleChanged();
|
||||||
|
void strokeChanged();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void handlePathChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paint(QPainter *p) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QQuickPath *m_path = nullptr;
|
||||||
|
QColor m_color = Qt::red;
|
||||||
|
qreal m_pathScale = 1.0;
|
||||||
|
Qt::FillRule m_fillRule = Qt::WindingFill;
|
||||||
|
Qt::PenStyle m_strokeStyle = Qt::NoPen;
|
||||||
|
QColor m_strokeColor = Qt::transparent;
|
||||||
|
qreal m_strokeWidth = 1.0;
|
||||||
|
Qt::PenCapStyle m_capStyle = Qt::FlatCap;
|
||||||
|
Qt::PenJoinStyle m_joinStyle = Qt::MiterJoin;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEBUGPAINTITEM_H
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
#include "debugvisualizationcontroller.h"
|
||||||
|
#include <private/qquickshapecurverenderer_p.h>
|
||||||
|
|
||||||
|
DebugVisualizationController::DebugVisualizationController(QObject *parent)
|
||||||
|
: QObject{parent}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DebugVisualizationController::showCurves() const
|
||||||
|
{
|
||||||
|
return m_showCurves;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugVisualizationController::setShowCurves(bool newShowCurves)
|
||||||
|
{
|
||||||
|
if (m_showCurves == newShowCurves)
|
||||||
|
return;
|
||||||
|
m_showCurves = newShowCurves;
|
||||||
|
update();
|
||||||
|
emit showCurvesChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DebugVisualizationController::showWireframe() const
|
||||||
|
{
|
||||||
|
return m_showWireframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugVisualizationController::setWireframe(bool newShowWireframe)
|
||||||
|
{
|
||||||
|
if (m_showWireframe == newShowWireframe)
|
||||||
|
return;
|
||||||
|
m_showWireframe = newShowWireframe;
|
||||||
|
update();
|
||||||
|
emit showWireframeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugVisualizationController::update()
|
||||||
|
{
|
||||||
|
int flags = (m_showCurves ? QQuickShapeCurveRenderer::DebugCurves : 0)
|
||||||
|
| (m_showWireframe ? QQuickShapeCurveRenderer::DebugWireframe : 0);
|
||||||
|
QQuickShapeCurveRenderer::setDebugVisualization(flags);
|
||||||
|
emit settingsChanged();
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
#ifndef DEBUGVISUALIZATIONCONTROLLER_H
|
||||||
|
#define DEBUGVISUALIZATIONCONTROLLER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class DebugVisualizationController : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(bool showCurves READ showCurves WRITE setShowCurves NOTIFY showCurvesChanged)
|
||||||
|
Q_PROPERTY(bool showWireframe READ showWireframe WRITE setWireframe NOTIFY showWireframeChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DebugVisualizationController(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
bool showCurves() const;
|
||||||
|
void setShowCurves(bool newShowCurves);
|
||||||
|
|
||||||
|
bool showWireframe() const;
|
||||||
|
void setWireframe(bool newShowWireframe);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void showCurvesChanged();
|
||||||
|
void showWireframeChanged();
|
||||||
|
void settingsChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void update();
|
||||||
|
bool m_showCurves = false;
|
||||||
|
bool m_showWireframe = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEBUGVISUALIZATIONCONTROLLER_H
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
Item {
|
||||||
|
ControlledShape {
|
||||||
|
id: shape
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height / 2
|
||||||
|
|
||||||
|
startX: 10
|
||||||
|
startY: 100
|
||||||
|
delegate: [
|
||||||
|
PathArc {
|
||||||
|
relativeX: 50
|
||||||
|
y: 100
|
||||||
|
radiusX: 25
|
||||||
|
radiusY: 25
|
||||||
|
},
|
||||||
|
PathArc {
|
||||||
|
relativeX: 50
|
||||||
|
y: 100
|
||||||
|
radiusX: 25
|
||||||
|
radiusY: 35
|
||||||
|
},
|
||||||
|
PathArc {
|
||||||
|
relativeX: 50
|
||||||
|
y: 100
|
||||||
|
radiusX: 25
|
||||||
|
radiusY: 60
|
||||||
|
},
|
||||||
|
PathArc {
|
||||||
|
relativeX: 50
|
||||||
|
y: 100
|
||||||
|
radiusX: 50
|
||||||
|
radiusY: 120
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height / 2
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
fillColor: "transparent"
|
||||||
|
strokeColor: "darkBlue"
|
||||||
|
strokeWidth: 20
|
||||||
|
capStyle: ShapePath.RoundCap
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathAngleArc {
|
||||||
|
centerX: 65
|
||||||
|
centerY: 95
|
||||||
|
radiusX: 45
|
||||||
|
radiusY: 45
|
||||||
|
startAngle: -180
|
||||||
|
SequentialAnimation on sweepAngle {
|
||||||
|
loops: Animation.Infinite
|
||||||
|
NumberAnimation {
|
||||||
|
to: 360
|
||||||
|
duration: 2000
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
to: 0
|
||||||
|
duration: 2000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
id: star
|
||||||
|
strokeColor: "blue"
|
||||||
|
fillColor: "magenta"
|
||||||
|
strokeWidth: 2
|
||||||
|
delegate: [
|
||||||
|
PathMove {
|
||||||
|
x: 90
|
||||||
|
y: 50
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
x: 50 + 40 * Math.cos(0.8 * 1 * Math.PI)
|
||||||
|
y: 50 + 40 * Math.sin(0.8 * 1 * Math.PI)
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
x: 50 + 40 * Math.cos(0.8 * 2 * Math.PI)
|
||||||
|
y: 50 + 40 * Math.sin(0.8 * 2 * Math.PI)
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
x: 50 + 40 * Math.cos(0.8 * 3 * Math.PI)
|
||||||
|
y: 50 + 40 * Math.sin(0.8 * 3 * Math.PI)
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
x: 50 + 40 * Math.cos(0.8 * 4 * Math.PI)
|
||||||
|
y: 50 + 40 * Math.sin(0.8 * 4 * Math.PI)
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
x: 90
|
||||||
|
y: 50
|
||||||
|
}
|
||||||
|
]
|
||||||
|
Timer {
|
||||||
|
interval: 2000
|
||||||
|
onTriggered: star.fillRule = (star.fillRule === ShapePath.OddEvenFill ? ShapePath.WindingFill : ShapePath.OddEvenFill)
|
||||||
|
repeat: true
|
||||||
|
running: true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
Item {
|
||||||
|
ControlledShape {
|
||||||
|
anchors.fill: parent
|
||||||
|
strokeColor: "transparent"
|
||||||
|
startX: 10
|
||||||
|
startY: 10
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathLine {
|
||||||
|
relativeX: 180
|
||||||
|
relativeY: 0
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
relativeX: 0
|
||||||
|
relativeY: 180
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
relativeX: -180
|
||||||
|
relativeY: 0
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
relativeX: 0
|
||||||
|
relativeY: -180
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: spreadTimer
|
||||||
|
interval: 3000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
readonly property variant spreads: [ ShapeGradient.PadSpread, ShapeGradient.RepeatSpread, ShapeGradient.ReflectSpread ]
|
||||||
|
readonly property variant spreadTexts: [ qsTr("PadSpread"), qsTr("RepeatSpread"), qsTr("ReflectSpread") ]
|
||||||
|
property int spreadIdx: 0
|
||||||
|
onTriggered: function() {
|
||||||
|
spreadIdx = (spreadIdx + 1) % spreads.length
|
||||||
|
grad.spread = spreads[spreadIdx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
anchors.fill: parent
|
||||||
|
strokeColor: "gray"
|
||||||
|
strokeWidth: 2
|
||||||
|
fillColor: "transparent"
|
||||||
|
delegate: [
|
||||||
|
PathMove {
|
||||||
|
x: 0
|
||||||
|
y: 50
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
relativeX: 200
|
||||||
|
relativeY: 0
|
||||||
|
},
|
||||||
|
PathMove {
|
||||||
|
x: 0
|
||||||
|
y: 150
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
relativeX: 200
|
||||||
|
relativeY: 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
<svg
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:ns1="http://sozi.baierouge.fr"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
id="svg10114"
|
||||||
|
sodipodi:docname="New document 114"
|
||||||
|
viewBox="0 0 210.55 207.21"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.4 r9939"
|
||||||
|
>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
bordercolor="#666666"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-y="170"
|
||||||
|
fit-margin-left="0"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
fit-margin-top="0"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:zoom="0.35"
|
||||||
|
inkscape:window-x="381"
|
||||||
|
inkscape:window-height="455"
|
||||||
|
showgrid="false"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:cx="177.4157"
|
||||||
|
inkscape:cy="37.888957"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:window-width="515"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
/>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
transform="translate(-197.58 -363.04)"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
id="path10106"
|
||||||
|
sodipodi:nodetypes="sssssssscssssssssssssssssssssssssssssscssssssssscsssssssssssassssssssssssssscscccssssssssssssssssscacasssssssssssssssssssscscc"
|
||||||
|
style="fill:#000000"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m322.61 371.62c-1.5377 0.0333-3.5271 0.80745-6.0938 2.25-4.9988 2.8095-6.3561 7.2849-5.4688 18.062 0.51964 6.3116 0.32732 8.239-1.0312 10.312-1.356 2.0695-1.5585 4.005-1.0625 10.438 0.33561 4.3521 1.1508 8.7842 1.8125 9.8438 0.96765 1.5495 0.87327 2.6094-0.46875 5.4375-2.049 4.3179-2.0715 5.7903-0.1875 8.2812 0.8075 1.0676 1.4825 2.5854 1.5 3.375 0.0175 0.78955 0.99163 2.477 2.1875 3.75 2.608 2.7761 3.0737 2.8262 5.0312 0.5625 3.1122-3.5987 3.9502-8.9023 4.375-28.031 0.31534-14.199 0.80913-20.033 1.875-22.094 0.80879-1.564 1.5884-6.3682 1.75-10.844 0.28534-7.9048-0.83575-11.417-4.2188-11.344zm-53 14.062c-1.9081 0-6.859 2.9524-7.8125 4.6562-1.1433 2.0429-0.39376 13.788 1.125 17.844 0.61791 1.65 1.9625 3.6232 3 4.375 1.1193 0.81114 1.6944 2.1169 1.4062 3.2188-0.69123 2.6432 0.97813 9.3176 3.8438 15.375 1.3522 2.8583 2.9145 7.6087 3.4688 10.531 0.55425 2.9226 2.2388 7.2762 3.75 9.6875 2.3396 3.7331 3.1564 4.3347 5.625 4.0938 3.7598-0.36694 5.5441-3.0273 3.8438-5.75-0.68348-1.0944-1.2188-3.1291-1.2188-4.5s-1.1024-5.7509-2.4375-9.75-2.4246-9.0812-2.4062-11.281c0.0184-2.2-0.46367-6.25-1.0938-9-1.0663-4.6539-4.014-21.112-4.0625-22.719-0.0353-1.1676-5.8553-6.7812-7.0312-6.7812zm87.719 2.1875c-3.4842-0.0817-7.1481 2.6491-8.6562 7.2188-1.0035 3.0406-2.0408 14.629-2.0938 23.594-0.0114 1.925-0.49233 5.0413-1.0938 6.9062-0.60142 1.8649-1.0482 5.3488-1 7.75 0.07 3.4862-0.5085 5.0547-2.875 7.75-3.4871 3.9716-4.1106 9.8469-1.2188 11.531 0.9625 0.56061 2.261 1.0146 2.9062 1.0312 2.0704 0.0537 7.3438-5.081 7.3438-7.1562 0-1.1038 0.64287-3.1964 1.4375-4.6562 2.6446-4.8585 7.6275-23.031 7-25.531-0.35831-1.4276 0.1021-3.7719 1.125-5.75 0.9498-1.8367 1.8627-4.9087 2.0312-6.8438 0.16858-1.935 0.60352-5.3826 0.96875-7.6562 0.54958-3.4212 0.28253-4.4987-1.4688-6.25-1.2836-1.2836-2.8225-1.9004-4.4062-1.9375zm38.962 39.776c-0.41087-1.3177-2.649-3.1827-2.649-3.1827-5.6222 0.62958-7.1736 1.4539-9.9688 5.3125-2.033 2.8064-3.124 5.767-3.5938 9.7188-0.50455 4.2441-1.3633 6.4493-3.4375 8.6875-1.5291 1.65-3.8228 5.0269-5.0625 7.5s-2.9062 4.9996-3.7188 5.5938c-1.7406 1.2728-6.1921 14.341-5.5 16.156 0.90097 2.3631 4.0452 1.26 7.4062-2.625 1.8515-2.1402 4.4737-5.1777 5.8438-6.75 4.0598-4.659 11.031-16.282 11.031-18.406 0-0.63241 0.9-2.2891 2-3.6875s2-3.3296 2-4.2812c0-2.1982 3.7305-4.6335 4.742-7.3758 0.77537-2.1021 1.6609-4.2424 0.90707-6.6602zm-107.4 33.88c-2.7007-0.0514-4.8692 0.33799-5.7812 1.25-0.9007 0.9007-1.6649 4.5217-2.0312 9.5938-0.61163 8.4673 0.68391 13.233 4.375 15.938 1.3221 0.96856 1.125 1.6325-1.625 4.9688-1.7472 2.1197-3.6988 1.3702-5.4885 2.2118-2.7058 1.2724-4.2526 5.347-4.5115 8.4758-0.19436 2.3492-1.2274 4.6649-2.75 6.1875-1.3413 1.3413-2.4375 3.5424-2.4375 4.875 0 1.3327-0.68534 2.9801-1.5 3.6562-1.5011 1.2458-7.4902 0.99608-10.75-0.4375-2.0861-0.91741-3.75 2.6725-3.75 8.0312 0 2.7703 1.0145 4.5375 5.2812 9.1562 17.679 19.138 24.149 24.25 30.625 24.25 1.6394 0 3.2137 0.42371 3.5312 0.9375 0.31753 0.51376 2.0351 0.73192 3.8125 0.46875 5.7811-0.85595 23.001-2.3031 33.219-2.7812l10-0.46875 3.5-3.9375c1.934-2.1628 5.0241-6.3457 6.8438-9.3125 2.7166-4.4293 3.2194-6.1294 2.8125-9.4062-0.34558-2.7831-0.0335-4.5077 1.0625-5.7188 1.1973-1.323 1.6274-4.4114 1.8125-13 0.16512-7.6629 0.77195-12.524 1.875-15.156 0.89247-2.1297 1.6388-4.8297 1.6562-6 0.0175-1.1703 0.6925-2.9949 1.5-4.0625 3.3493-4.4282 0.60788-8.5625-5.6875-8.5625-3.1563 0-4.9116-0.75392-8.1562-3.5312-2.2727-1.9453-5.2665-3.8195-6.6562-4.1562-1.3898-0.33673-3.4151-1.2258-4.5-1.9688-1.0849-0.74294-2.614-1.3438-3.375-1.3438-0.76098 0-3.0271-1.2925-5.0312-2.875-4.3642-3.446-12.675-4.9864-17.094-3.1562-2.3602 0.97763-3.4086 0.8936-6.1875-0.5625-4.1163-2.1568-10.093-3.4769-14.594-3.5625zm-73.375 17.938c-1.3882-0.0661-2.5361 0.22802-4.2812 0.84375-2.1608 0.7624-2.8143 1.7251-3.6496 3.0802-0.96454 1.5646-1.225 3.8922-1.2843 5.3625-0.0716 1.7769 0.60748 3.6445 1.6214 5.1199 2.4979 3.6347 4.7532 2.6468 10.344 8.25 4.7079 4.7186 9.3065 8.5625 10.25 8.5625 0.94347 0 3.2613 1.125 5.125 2.5 4.0233 2.9683 6.95 3.1826 10.031 0.6875 2.9687-2.4039 2.1009-6.0679-2-8.375-2.5053-1.4095-3.0312-2.3588-3.0312-5.375 0-8.2634-7.1413-16.183-17.438-19.344-2.671-0.81994-4.2994-1.2464-5.6875-1.3125zm87.781 15.844c0.43126 0.007 0.89972 0.14969 1.4375 0.4375 2.3391 1.2518 14.915 1.6771 16.719 0.5625 2.3457-1.4497 2.6432 0.3729 0.65625 4.0625-1.5014 2.7879-1.9615 5.6783-2 12.719-0.0274 5.0078-0.38695 9.6562-0.8125 10.344-0.92832 1.4998-3.2958 1.6422-4.1562 0.25-0.33992-0.55-1.9394-1-3.5312-1-1.9787 0-3.4592-0.80091-4.6875-2.5625-0.98817-1.4172-3.0717-3.9871-4.6562-5.6875-2.7528-2.9542-2.8667-3.3899-2.3125-10 0.54096-6.4526 1.475-9.157 3.3438-9.125zm94.438 65.938c0.24133 0.40465 0.5482 0.4375 0.90625 0.4375 0.31607 0 0.55718-0.0265 0.78125-0.4375z"
|
||||||
|
/>
|
||||||
|
</g
|
||||||
|
>
|
||||||
|
<metadata
|
||||||
|
>
|
||||||
|
<rdf:RDF
|
||||||
|
>
|
||||||
|
<cc:Work
|
||||||
|
>
|
||||||
|
<dc:format
|
||||||
|
>image/svg+xml</dc:format
|
||||||
|
>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage"
|
||||||
|
/>
|
||||||
|
<cc:license
|
||||||
|
rdf:resource="http://creativecommons.org/licenses/publicdomain/"
|
||||||
|
/>
|
||||||
|
<dc:publisher
|
||||||
|
>
|
||||||
|
<cc:Agent
|
||||||
|
rdf:about="http://openclipart.org/"
|
||||||
|
>
|
||||||
|
<dc:title
|
||||||
|
>Openclipart</dc:title
|
||||||
|
>
|
||||||
|
</cc:Agent
|
||||||
|
>
|
||||||
|
</dc:publisher
|
||||||
|
>
|
||||||
|
</cc:Work
|
||||||
|
>
|
||||||
|
<cc:License
|
||||||
|
rdf:about="http://creativecommons.org/licenses/publicdomain/"
|
||||||
|
>
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Reproduction"
|
||||||
|
/>
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Distribution"
|
||||||
|
/>
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#DerivativeWorks"
|
||||||
|
/>
|
||||||
|
</cc:License
|
||||||
|
>
|
||||||
|
</rdf:RDF
|
||||||
|
>
|
||||||
|
</metadata
|
||||||
|
>
|
||||||
|
</svg
|
||||||
|
>
|
After Width: | Height: | Size: 7.4 KiB |
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
strokeColor: "black"
|
||||||
|
strokeWidth: 16
|
||||||
|
fillColor: "transparent"
|
||||||
|
capStyle: ShapePath.RoundCap
|
||||||
|
|
||||||
|
//readonly property variant styles: [ ShapePath.BevelJoin, ShapePath.MiterJoin, ShapePath.RoundJoin ]
|
||||||
|
//joinStyle: styles[joinStyleIdx]
|
||||||
|
|
||||||
|
property int joinStyleIdx: 0
|
||||||
|
readonly property variant styles: [ ShapePath.BevelJoin, ShapePath.MiterJoin, ShapePath.RoundJoin ]
|
||||||
|
readonly property variant styleTexts: [ qsTr("BevelJoin"), qsTr("MiterJoin"), qsTr("RoundJoin") ]
|
||||||
|
|
||||||
|
startX: 30
|
||||||
|
startY: 30
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathLine {
|
||||||
|
x: 100
|
||||||
|
y: 100
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
x: 30
|
||||||
|
y: 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// Timer {
|
||||||
|
// interval: 1000
|
||||||
|
// repeat: true
|
||||||
|
// running: true
|
||||||
|
// onTriggered: joinTest.joinStyleIdx = (joinTest.joinStyleIdx + 1) % joinTest.styles.length
|
||||||
|
// }
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Repeater {
|
||||||
|
anchors.fill: parent
|
||||||
|
model: 2
|
||||||
|
delegate: ControlledShape {
|
||||||
|
id: delegate
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
fillColor: "transparent"
|
||||||
|
strokeColor: delegate.index === 0 ? "red" : "blue"
|
||||||
|
strokeStyle: ShapePath.DashLine
|
||||||
|
strokeWidth: 4
|
||||||
|
startX: 50
|
||||||
|
startY: 100
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathArc {
|
||||||
|
x: 100
|
||||||
|
y: 150
|
||||||
|
radiusX: 50
|
||||||
|
radiusY: 50
|
||||||
|
useLargeArc: delegate.index === 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
strokeWidth: 4
|
||||||
|
strokeColor: "red"
|
||||||
|
// fillGradient: LinearGradient {
|
||||||
|
// x1: 20
|
||||||
|
// y1: 20
|
||||||
|
// x2: 180
|
||||||
|
// y2: 130
|
||||||
|
// GradientStop {
|
||||||
|
// position: 0
|
||||||
|
// color: "blue"
|
||||||
|
// }
|
||||||
|
// GradientStop {
|
||||||
|
// position: 0.2
|
||||||
|
// color: "green"
|
||||||
|
// }
|
||||||
|
// GradientStop {
|
||||||
|
// position: 0.4
|
||||||
|
// color: "red"
|
||||||
|
// }
|
||||||
|
// GradientStop {
|
||||||
|
// position: 0.6
|
||||||
|
// color: "yellow"
|
||||||
|
// }
|
||||||
|
// GradientStop {
|
||||||
|
// position: 1
|
||||||
|
// color: "cyan"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
fillColor: "blue" // ignored with the gradient set
|
||||||
|
strokeStyle: ShapePath.DashLine
|
||||||
|
// dashPattern: [ 1, 4 ]
|
||||||
|
startX: 20
|
||||||
|
startY: 20
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathLine {
|
||||||
|
x: 180
|
||||||
|
y: 130
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
x: 20
|
||||||
|
y: 130
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
x: 20
|
||||||
|
y: 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// transform: Rotation {
|
||||||
|
// origin.x: 100
|
||||||
|
// origin.y: 50
|
||||||
|
// axis {
|
||||||
|
// x: 0
|
||||||
|
// y: 1
|
||||||
|
// z: 0
|
||||||
|
// }
|
||||||
|
// SequentialAnimation on angle {
|
||||||
|
// NumberAnimation {
|
||||||
|
// from: 0
|
||||||
|
// to: 75
|
||||||
|
// duration: 2000
|
||||||
|
// }
|
||||||
|
// NumberAnimation {
|
||||||
|
// from: 75
|
||||||
|
// to: -75
|
||||||
|
// duration: 4000
|
||||||
|
// }
|
||||||
|
// NumberAnimation {
|
||||||
|
// from: -75
|
||||||
|
// to: 0
|
||||||
|
// duration: 2000
|
||||||
|
// }
|
||||||
|
// loops: Animation.Infinite
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
#include <QFontDatabase>
|
||||||
|
|
||||||
|
#include "svgpathloader.h"
|
||||||
|
#include "debugpaintitem.h"
|
||||||
|
#include "debugvisualizationcontroller.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
#endif
|
||||||
|
QGuiApplication app(argc, argv);
|
||||||
|
|
||||||
|
qmlRegisterType<DebugPaintItem>("io.qt", 1, 0, "DebugPaintItem");
|
||||||
|
qmlRegisterType<SvgPathLoader>("io.qt", 1, 0, "SvgPathLoader");
|
||||||
|
qmlRegisterType<DebugVisualizationController>("io.qt", 1, 0, "DebugVisualizationController");
|
||||||
|
|
||||||
|
QFontDatabase::addApplicationFont(":/Graziano.ttf");
|
||||||
|
QQmlApplicationEngine engine;
|
||||||
|
const QUrl url(QStringLiteral("qrc:/main.qml"));
|
||||||
|
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
|
||||||
|
&app, [url](QObject *obj, const QUrl &objUrl) {
|
||||||
|
if (!obj && url == objUrl)
|
||||||
|
QCoreApplication::exit(-1);
|
||||||
|
}, Qt::QueuedConnection);
|
||||||
|
engine.load(url);
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
|
@ -0,0 +1,189 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Window
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
Window {
|
||||||
|
width: 1024
|
||||||
|
height: 768
|
||||||
|
visible: true
|
||||||
|
title: qsTr("Hello World")
|
||||||
|
color: "#666"
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
id: sampleList
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Small polygon"
|
||||||
|
source: "SmallPolygon.qml"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Text"
|
||||||
|
source: "TextShape.qml"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "SVG"
|
||||||
|
source: "SvgShape.qml"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "QuadShape"
|
||||||
|
source: "SimpleShape.qml"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Squircle"
|
||||||
|
source: "Squircle.qml"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "CubicShape"
|
||||||
|
source: "CubicShape.qml"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
text: "Arc Direction"
|
||||||
|
source: "arcDirection.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Arc Rotation"
|
||||||
|
source: "arcRotation.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Cap Styles"
|
||||||
|
source: "capStyles.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Cubic Curve"
|
||||||
|
source: "cubicCurve.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Dash Pattern"
|
||||||
|
source: "dashPattern.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Elliptical Arcs"
|
||||||
|
source: "ellipticalArcs.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Fill rules"
|
||||||
|
source: "fillRules.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Gradient spread modes"
|
||||||
|
source: "gradientSpreadModes.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Join styles"
|
||||||
|
source: "joinStyles.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Large or small arc"
|
||||||
|
source: "largeOrSmallArc.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Linear gradient"
|
||||||
|
source: "linearGradient.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Quadratic curve"
|
||||||
|
source: "quadraticCurve.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Radial gradient"
|
||||||
|
source: "radialGradient.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Stroke or fill"
|
||||||
|
source: "strokeOrFill.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Qt! text"
|
||||||
|
source: "text.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
text: "Tiger"
|
||||||
|
source: "tiger.qml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: comboBox
|
||||||
|
model: sampleList
|
||||||
|
textRole: "text"
|
||||||
|
valueRole: "source"
|
||||||
|
onCurrentValueChanged: {
|
||||||
|
loader.source = currentValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Image {
|
||||||
|
id: background
|
||||||
|
anchors.fill: flickable
|
||||||
|
fillMode: Image.Tile
|
||||||
|
source: "qrc:/background.png"
|
||||||
|
smooth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Flickable {
|
||||||
|
id: flickable
|
||||||
|
clip: true
|
||||||
|
contentWidth: loader.item ? loader.item.boundingRect.right * controlPanel.scale + controlPanel.pathMargin * 2 : 1
|
||||||
|
contentHeight: loader.item ? loader.item.boundingRect.bottom * controlPanel.scale + controlPanel.pathMargin * 2 : 1
|
||||||
|
anchors.top: comboBox.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: controlPanel.top
|
||||||
|
|
||||||
|
WheelHandler {
|
||||||
|
onWheel: (event)=> {
|
||||||
|
let scale = controlPanel.scale
|
||||||
|
let posX = event.x
|
||||||
|
let posY = event.y
|
||||||
|
let xOff = posX - flickable.contentX
|
||||||
|
let yOff = posY - flickable.contentY
|
||||||
|
|
||||||
|
let pathX = posX / scale
|
||||||
|
let pathY = posY / scale
|
||||||
|
|
||||||
|
if (event.angleDelta.y > 0)
|
||||||
|
scale = scale * 1.1
|
||||||
|
else
|
||||||
|
scale = scale / 1.1
|
||||||
|
controlPanel.setScale(scale)
|
||||||
|
|
||||||
|
flickable.contentX = pathX * controlPanel.scale - xOff
|
||||||
|
flickable.contentY = pathY * controlPanel.scale - yOff
|
||||||
|
flickable.returnToBounds()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
x: controlPanel.pathMargin
|
||||||
|
y: controlPanel.pathMargin
|
||||||
|
id: loader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlPanel {
|
||||||
|
id: controlPanel
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: parent.height / 4
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.4 r9939"
|
||||||
|
width="330.31769"
|
||||||
|
height="652.32654"
|
||||||
|
sodipodi:docname="166413_160676353985218_105678756151645_360714_7013010_n.jpg">
|
||||||
|
<metadata
|
||||||
|
id="metadata8">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs6" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1280"
|
||||||
|
inkscape:window-height="749"
|
||||||
|
id="namedview4"
|
||||||
|
showgrid="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:zoom="0.76005001"
|
||||||
|
inkscape:cx="162.4278"
|
||||||
|
inkscape:cy="342.07912"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="26"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg2" />
|
||||||
|
<g
|
||||||
|
id="g3001"
|
||||||
|
transform="translate(-120.24391,40.527705)">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ssssssssczsssssss"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path2999"
|
||||||
|
d="m 333.68126,543.99038 c -6.91753,-4.38697 -11.36161,-10.23632 -13.34555,-17.56558 -1.93876,-7.16237 -17.29569,-22.30618 -25.49276,-31.28027 -5.66358,-6.20045 -10.53284,-9.06593 -4.03049,-16.38723 5.60876,-6.31517 11.66711,-27.57804 12.39492,-33.72331 0.89475,-7.55473 19.88838,13.07827 29.55699,12.32647 15.07492,-1.17218 19.87293,-8.57979 31.333,-21.95526 9.95433,-11.61808 15.38922,-24.72893 21.56477,-35.66576 3.10302,-5.49543 14.54668,-28.68741 15.54455,-27.78873 2.65231,2.82162 7.60302,15.21755 8.9266,25.36832 1.32359,10.15076 1.33221,24.47455 5.4914,37.36519 3.70609,11.48633 2.22562,32.47582 -3.24615,46.02256 -2.19534,5.43511 -13.41276,12.171 -28.30712,34.76544 -2.04972,3.1094 -5.63972,6.63261 -9.09235,8.92323 -3.1379,2.08181 -9.31989,7.24499 -13.73775,11.47372 -4.41786,4.22873 -9.45802,8.42578 -11.20034,9.32677 -4.95722,2.56348 -11.13434,2.10828 -16.35972,-1.20556 z"
|
||||||
|
style="fill:#000000" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ssssssssssssssssscssss"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path2997"
|
||||||
|
d="m 236.5,478.28799 c -26.46888,-1.7341 -59.59471,-6.73425 -65.76997,-9.9276 -3.78272,-1.95612 -8.3648,-9.36928 -9.82546,-15.89622 -1.67608,-7.48953 -0.60289,-28.26342 1.85793,-35.96417 1.05453,-3.3 4.9189,-13.03322 8.58748,-21.62937 C 179.00832,376.92572 182,372.28356 182,363.21743 c 0,-3.50469 0.61152,-7.83574 1.35894,-9.62455 1.49509,-3.57827 2.36599,-9.42794 23.40534,-17.67708 15.33826,-6.01386 25.16813,-11.90646 32.74071,-18.37591 12.3733,-10.57084 26.6062,-13.06992 48.57877,-7.38876 17.54428,4.5362 25.34686,7.84887 38.9754,7.84887 6.08978,0 17.19611,-0.85492 18.24842,-0.29174 1.11527,0.59687 1.27225,5.31825 2.21511,8.56158 1.33843,4.60404 1.41526,7.68415 0.44529,11.54174 -2.05134,8.15817 -9.32024,15.59461 -13.88659,17.61453 -5.06052,2.23851 -16.40257,4.51284 -31.25983,5.67633 -14.7923,1.15841 -19.21657,-0.79634 -27.99177,15.58765 l -3.31538,6.19009 10.91268,15.36198 c 11.78018,16.58318 17.44498,48.05873 11.58963,61.65598 -3.10121,7.2016 -8.24447,17.64394 -14.43161,22.20637 -9.7269,7.17267 -28.89257,-2.88671 -43.08511,-3.81652 z"
|
||||||
|
style="fill:#000000" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ssaaaasscss"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path2995"
|
||||||
|
d="m 317.68552,447.77108 c -4.67916,-1.18677 -9.1372,-7.95998 -9.65154,-12.98136 -0.48763,-4.76058 3.66294,-14.83262 6.92258,-21.68422 4.49604,-9.45044 11.55001,-17.4567 17.1823,-26.27727 5.4084,-8.46995 10.65679,-17.0411 15.94923,-25.58399 7.17401,-11.58005 7.84367,-33.73833 21.42439,-34.80044 14.18977,-1.10974 28.2626,27.80345 27.76586,32.43896 -1.92945,18.00547 -12.74615,35.2835 -22.17876,51.23197 -6.61784,11.18931 -11.77374,15.63521 -18.1815,27.31116 -4.3386,7.809 -9.17117,10.7187 -17.04193,15.96767 -8.33187,5.55649 -19.11228,-4.84172 -22.19063,-5.62248 z"
|
||||||
|
style="fill:#000000" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="csssassaasc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path2993"
|
||||||
|
d="m 297.7121,397.62093 c -4.37978,-0.76378 -11.1662,-5.35567 -13.43054,-9.08751 -1.05408,-1.73722 -5.27599,-4.42533 -4.52995,-6.66133 3.79539,-11.37539 8.14861,-15.05527 11.11936,-17.01179 1.47519,-0.97155 10.91285,-2.35405 16.45476,-2.37949 5.35694,-0.0246 14.398,2.6739 15.926,2.15393 6.39248,-2.1753 21.58665,-11.63284 16.66639,-3.95961 -1.74425,2.72018 -9.86689,20.36174 -15.66412,30.05992 -2.80151,4.68665 -3.99996,11.91427 -9.21074,13.54551 -5.90623,1.84894 -15.24781,-6.29628 -17.33116,-6.65959 z"
|
||||||
|
style="fill:#000000" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ssssssssssccssssccsssscssccssssscss"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path2991"
|
||||||
|
d="m 189,334.76618 c -3.56886,-1.87317 -3.73828,-7.15428 -0.55687,-17.35819 5.01517,-16.0854 8.92638,-21.55121 8.92639,-47.57388 2e-5,-23.36514 -3.95828,-35.38789 -7.18098,-47.31903 -1.78273,-6.6 -3.77628,-16.86508 -6.83769,-24.01508 -8.99294,-21.00325 -12.2685,-31.92583 -13.8777,-46.27612 C 168.53694,143.87507 165.62544,129.70037 161.00571,111 152.60865,77.00927 151.53855,67.780331 154.95103,58.78242 158.45942,49.531613 167.63712,43 177.12722,43 c 5.76576,0 14.29179,3.435547 18.43755,7.429376 4.91773,4.73752 12.26688,9.449135 15.70129,28.754921 2.71875,14.37298 5.5615,30.709973 7.68228,44.315703 2.82481,18.38886 4.9316,24.88951 8.2153,32.19284 5.77357,12.84108 9.22986,29.46676 11.71356,50.30716 0.55716,4.675 2.6273,13.9 4.60031,20.5 1.97301,6.6 4.35732,12.20086 5.75964,13.99194 4.31214,5.50757 4.20182,11.46411 9.8041,16.33937 4.89284,3.932 5.17553,-4.93168 8.48229,-8.86127 5.04933,-6.00079 4.34525,-17.53657 9.98389,-34.12517 6.53313,-19.22016 5.46933,-38.15405 19.40326,-68.32952 12.90365,-27.94429 9.48745,-39.81066 16.06865,-59.54708 6.06973,-18.202577 7.65173,-41.314931 21.79742,-54.279307 6.74694,-6.183506 18.29831,-8.217335 26.58616,-6.854856 8.28785,1.362479 17.87216,3.615793 19.20995,12.536783 0.8831,5.888923 2.70582,18.266918 -3.21886,39.099813 -6.49981,22.855208 -13.44316,35.388777 -16.01082,52.270797 -6.1548,20.88948 -8.08415,24.9957 -13.41238,50.5742 -4.92944,22.91145 -9.053,30.98714 -15.44314,44.38602 -4.78823,10.03997 -5.29352,16.18349 -7.50248,25.34215 -1.64534,6.82178 -4.51529,18.70324 -6.37768,26.40324 -3.3461,13.83435 -11.83198,26.93346 -15.1878,30.64161 -2.62156,2.89679 -7.70019,2.39802 -22.59508,-2.21904 -8.11727,-2.51617 -16.06028,-4.30586 -20.32463,-4.57947 -11.21682,-1.7957 -18.88746,8.09995 -28,14.65341 -27.91809,20.07783 -36.8097,24.33407 -43.5,20.82256 z"
|
||||||
|
style="fill:#000000" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cscsssssssccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path2987"
|
||||||
|
d="m 338,310.79118 c -1.925,-0.46211 -8.55748,-0.57196 -14.73884,-0.24413 l -11.23883,0.59606 -1.16709,-2.56149 c -1.04742,-2.29882 -0.4417,-4.02378 5.9069,-16.82155 C 320.65283,283.91703 324.74157,274.35 325.84822,270.5 327.62523,264.31785 333,241.17153 333,239.70102 c 0,-0.30699 0.70714,-1.26531 1.57143,-2.12959 2.10347,-2.10348 9.18161,-2.03578 17.79224,0.17017 5.65285,1.4482 7.36756,2.39455 9.72002,5.36446 6.48214,8.18349 21.03837,15.40973 14.91994,28.32586 -1.41866,14.95087 -7.97079,34.16095 -14.83219,45.02554 C 359.76469,319.83743 342.69403,311.918 338,310.79118 z"
|
||||||
|
style="fill:#000000" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.9 KiB |
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
Item {
|
||||||
|
ControlledShape {
|
||||||
|
id: shape
|
||||||
|
anchors.fill: parent
|
||||||
|
strokeWidth: 4
|
||||||
|
strokeColor: "black"
|
||||||
|
fillColor: "transparent"
|
||||||
|
|
||||||
|
startX: 50
|
||||||
|
startY: 50
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathQuad {
|
||||||
|
x: 150
|
||||||
|
y: 50
|
||||||
|
controlX: cp.x
|
||||||
|
controlY: cp.y
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: cp
|
||||||
|
color: "red"
|
||||||
|
width: 10
|
||||||
|
height: 10
|
||||||
|
SequentialAnimation on x {
|
||||||
|
loops: Animation.Infinite
|
||||||
|
NumberAnimation {
|
||||||
|
from: 0
|
||||||
|
to: shape.width - cp.width
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
from: shape.width - cp.width
|
||||||
|
to: 0
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
// fillGradient: RadialGradient {
|
||||||
|
// centerX: 100
|
||||||
|
// centerY: 100
|
||||||
|
// centerRadius: 100
|
||||||
|
// SequentialAnimation on focalRadius {
|
||||||
|
// loops: Animation.Infinite
|
||||||
|
// NumberAnimation {
|
||||||
|
// from: 1
|
||||||
|
// to: 20
|
||||||
|
// duration: 2000
|
||||||
|
// }
|
||||||
|
// NumberAnimation {
|
||||||
|
// from: 20
|
||||||
|
// to: 1
|
||||||
|
// duration: 2000
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// SequentialAnimation on focalX {
|
||||||
|
// loops: Animation.Infinite
|
||||||
|
// NumberAnimation {
|
||||||
|
// from: 50
|
||||||
|
// to: 150
|
||||||
|
// duration: 3000
|
||||||
|
// }
|
||||||
|
// NumberAnimation {
|
||||||
|
// from: 150
|
||||||
|
// to: 50
|
||||||
|
// duration: 3000
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// SequentialAnimation on focalY {
|
||||||
|
// loops: Animation.Infinite
|
||||||
|
// NumberAnimation {
|
||||||
|
// from: 50
|
||||||
|
// to: 150
|
||||||
|
// duration: 1000
|
||||||
|
// }
|
||||||
|
// NumberAnimation {
|
||||||
|
// from: 150
|
||||||
|
// to: 50
|
||||||
|
// duration: 1000
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// GradientStop {
|
||||||
|
// position: 0
|
||||||
|
// color: "#ffffff"
|
||||||
|
// }
|
||||||
|
// GradientStop {
|
||||||
|
// position: 0.11
|
||||||
|
// color: "#f9ffa0"
|
||||||
|
// }
|
||||||
|
// GradientStop {
|
||||||
|
// position: 0.13
|
||||||
|
// color: "#f9ff99"
|
||||||
|
// }
|
||||||
|
// GradientStop {
|
||||||
|
// position: 0.14
|
||||||
|
// color: "#f3ff86"
|
||||||
|
// }
|
||||||
|
// GradientStop {
|
||||||
|
// position: 0.49
|
||||||
|
// color: "#93b353"
|
||||||
|
// }
|
||||||
|
// GradientStop {
|
||||||
|
// position: 0.87
|
||||||
|
// color: "#264619"
|
||||||
|
// }
|
||||||
|
// GradientStop {
|
||||||
|
// position: 0.96
|
||||||
|
// color: "#0c1306"
|
||||||
|
// }
|
||||||
|
// GradientStop {
|
||||||
|
// position: 1
|
||||||
|
// color: "#000000"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
strokeWidth: 4
|
||||||
|
strokeColor: "red"
|
||||||
|
fillColor: "blue" // ignored with the gradient set
|
||||||
|
strokeStyle: ShapePath.DashLine
|
||||||
|
//dashPattern: [ 1, 4 ]
|
||||||
|
startX: 20
|
||||||
|
startY: 20
|
||||||
|
delegate: [
|
||||||
|
PathLine {
|
||||||
|
x: 180
|
||||||
|
y: 130
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
x: 20
|
||||||
|
y: 130
|
||||||
|
},
|
||||||
|
PathLine {
|
||||||
|
x: 20
|
||||||
|
y: 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
Item {
|
||||||
|
ControlledShape {
|
||||||
|
id: circ1
|
||||||
|
anchors.fill: parent
|
||||||
|
fillColor: "transparent" // stroke only
|
||||||
|
strokeWidth: 4
|
||||||
|
|
||||||
|
SequentialAnimation on strokeColor {
|
||||||
|
loops: Animation.Infinite
|
||||||
|
ColorAnimation {
|
||||||
|
from: "black"
|
||||||
|
to: "yellow"
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
ColorAnimation {
|
||||||
|
from: "yellow"
|
||||||
|
to: "green"
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
ColorAnimation {
|
||||||
|
from: "green"
|
||||||
|
to: "black"
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property real r: 60
|
||||||
|
startX: circ1.width / 2 - r
|
||||||
|
startY: circ1.height / 2 - r
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathArc {
|
||||||
|
x: circ1.width / 2 + circ1.r
|
||||||
|
y: circ1.height / 2 + circ1.r
|
||||||
|
radiusX: circ1.r
|
||||||
|
radiusY: circ1.r
|
||||||
|
useLargeArc: true
|
||||||
|
},
|
||||||
|
PathArc {
|
||||||
|
x: circ1.width / 2 - circ1.r
|
||||||
|
y: circ1.height / 2 - circ1.r
|
||||||
|
radiusX: circ1.r
|
||||||
|
radiusY: circ1.r
|
||||||
|
useLargeArc: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
id: circ2
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
SequentialAnimation on opacity {
|
||||||
|
loops: Animation.Infinite
|
||||||
|
NumberAnimation {
|
||||||
|
from: 1.0
|
||||||
|
to: 0.0
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
from: 0.0
|
||||||
|
to: 1.0
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strokeWidth: -1 // or strokeColor: "transparent"
|
||||||
|
|
||||||
|
SequentialAnimation on fillColor {
|
||||||
|
loops: Animation.Infinite
|
||||||
|
ColorAnimation {
|
||||||
|
from: "gray"
|
||||||
|
to: "purple"
|
||||||
|
duration: 3000
|
||||||
|
}
|
||||||
|
ColorAnimation {
|
||||||
|
from: "purple"
|
||||||
|
to: "red"
|
||||||
|
duration: 3000
|
||||||
|
}
|
||||||
|
ColorAnimation {
|
||||||
|
from: "red"
|
||||||
|
to: "gray"
|
||||||
|
duration: 3000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property real r: 40
|
||||||
|
startX: circ2.width / 2 - r
|
||||||
|
startY: circ2.height / 2 - r
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathArc {
|
||||||
|
x: circ2.width / 2 + circ2.r
|
||||||
|
y: circ2.height / 2 + circ2.r
|
||||||
|
radiusX: circ2.r
|
||||||
|
radiusY: circ2.r
|
||||||
|
useLargeArc: true
|
||||||
|
},
|
||||||
|
PathArc {
|
||||||
|
x: circ2.width / 2 - circ2.r
|
||||||
|
y: circ2.height / 2 - circ2.r
|
||||||
|
radiusX: circ2.r
|
||||||
|
radiusY: circ2.r
|
||||||
|
useLargeArc: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
#include "svgpathloader.h"
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QPainterPath>
|
||||||
|
#include <QtSvg/private/qsvgtinydocument_p.h>
|
||||||
|
#include <QtSvg/private/qsvggraphics_p.h>
|
||||||
|
|
||||||
|
SvgPathLoader::SvgPathLoader()
|
||||||
|
{
|
||||||
|
connect(this, &SvgPathLoader::sourceChanged, this, &SvgPathLoader::loadPaths);
|
||||||
|
|
||||||
|
loadPaths();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgPathLoader::loadPaths()
|
||||||
|
{
|
||||||
|
m_paths.clear();
|
||||||
|
m_fillColors.clear();
|
||||||
|
if (m_source.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString fileName;
|
||||||
|
if (m_source.isLocalFile())
|
||||||
|
fileName = m_source.toLocalFile();
|
||||||
|
else if (m_source.scheme() == QStringLiteral("qrc"))
|
||||||
|
fileName = QStringLiteral(":/") + m_source.fileName();
|
||||||
|
|
||||||
|
QFile f(fileName);
|
||||||
|
if (f.open(QIODevice::ReadOnly)) {
|
||||||
|
QXmlStreamReader reader(&f);
|
||||||
|
QString fillColor = QStringLiteral("#ffffff");
|
||||||
|
while (!reader.atEnd()) {
|
||||||
|
reader.readNext();
|
||||||
|
QXmlStreamAttributes attrs = reader.attributes();
|
||||||
|
if (reader.isStartElement() && attrs.hasAttribute(QStringLiteral("fill")))
|
||||||
|
fillColor = attrs.value(QStringLiteral("fill")).toString();
|
||||||
|
if (reader.isStartElement() && reader.name() == QStringLiteral("path")) {
|
||||||
|
m_fillColors.append(fillColor);
|
||||||
|
if (attrs.hasAttribute(QStringLiteral("d")))
|
||||||
|
m_paths.append(attrs.value(QStringLiteral("d")).toString());
|
||||||
|
if (attrs.hasAttribute(QStringLiteral("fill"))) {
|
||||||
|
m_fillColors[m_fillColors.size() - 1] = attrs.value(QStringLiteral("fill")).toString();
|
||||||
|
} else if (attrs.hasAttribute(QStringLiteral("style"))) {
|
||||||
|
QString s = attrs.value(QStringLiteral("style")).toString();
|
||||||
|
int idx = s.indexOf(QStringLiteral("fill:"));
|
||||||
|
if (idx >= 0) {
|
||||||
|
idx = s.indexOf(QLatin1Char('#'), idx);
|
||||||
|
if (idx >= 0)
|
||||||
|
m_fillColors[m_fillColors.size() - 1] = s.mid(idx, 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qWarning() << "Can't open file" << fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit pathsChanged();
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
#ifndef SVGPATHLOADER_H
|
||||||
|
#define SVGPATHLOADER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QPainterPath>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
class SvgPathLoader : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
|
||||||
|
Q_PROPERTY(QStringList paths READ paths NOTIFY pathsChanged)
|
||||||
|
Q_PROPERTY(QStringList fillColors READ fillColors NOTIFY pathsChanged)
|
||||||
|
public:
|
||||||
|
SvgPathLoader();
|
||||||
|
|
||||||
|
QUrl source() const
|
||||||
|
{
|
||||||
|
return m_source;
|
||||||
|
}
|
||||||
|
void setSource(const QUrl &url)
|
||||||
|
{
|
||||||
|
if (url == m_source)
|
||||||
|
return;
|
||||||
|
m_source = url;
|
||||||
|
qDebug() << "Set source" << url;
|
||||||
|
emit sourceChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList paths() const
|
||||||
|
{
|
||||||
|
return m_paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList fillColors() const
|
||||||
|
{
|
||||||
|
return m_fillColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void loadPaths();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sourceChanged();
|
||||||
|
void pathsChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QUrl m_source;
|
||||||
|
QStringList m_paths;
|
||||||
|
QStringList m_fillColors;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SVGPATHLOADER_H
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
ControlledShape {
|
||||||
|
strokeColor: "black"
|
||||||
|
strokeWidth: 1
|
||||||
|
fillColor: "black"
|
||||||
|
|
||||||
|
delegate: [
|
||||||
|
PathText {
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
text: qsTr("Qt!")
|
||||||
|
font.family: "Arial"
|
||||||
|
font.pixelSize: 150
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue