implementation of QskStippleMetrics completed

This commit is contained in:
Uwe Rathmann 2023-05-25 14:52:54 +02:00
parent 5d3cba5650
commit d84e75a3d1
10 changed files with 358 additions and 5 deletions

View File

@ -116,6 +116,7 @@ list(APPEND HEADERS
nodes/QskScaleRenderer.h nodes/QskScaleRenderer.h
nodes/QskSGNode.h nodes/QskSGNode.h
nodes/QskStrokeNode.h nodes/QskStrokeNode.h
nodes/QskStippledLineRenderer.h
nodes/QskShapeNode.h nodes/QskShapeNode.h
nodes/QskGradientMaterial.h nodes/QskGradientMaterial.h
nodes/QskTextNode.h nodes/QskTextNode.h
@ -146,6 +147,7 @@ list(APPEND SOURCES
nodes/QskScaleRenderer.cpp nodes/QskScaleRenderer.cpp
nodes/QskSGNode.cpp nodes/QskSGNode.cpp
nodes/QskStrokeNode.cpp nodes/QskStrokeNode.cpp
nodes/QskStippledLineRenderer.cpp
nodes/QskShapeNode.cpp nodes/QskShapeNode.cpp
nodes/QskGradientMaterial.cpp nodes/QskGradientMaterial.cpp
nodes/QskTextNode.cpp nodes/QskTextNode.cpp

View File

@ -16,11 +16,19 @@ static void qskRegisterStippleMetrics()
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) #if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QMetaType::registerEqualsComparator< QskStippleMetrics >(); QMetaType::registerEqualsComparator< QskStippleMetrics >();
#endif #endif
QMetaType::registerConverter< QPen, QskStippleMetrics >(
[]( const QPen& pen ) { return QskStippleMetrics( pen ); } );
QMetaType::registerConverter< Qt::PenStyle, QskStippleMetrics >(
[]( Qt::PenStyle style ) { return QskStippleMetrics( style ); } );
} }
static inline QVector< qreal > qskDashPattern( const Qt::PenStyle& style ) Q_CONSTRUCTOR_FUNCTION( qskRegisterStippleMetrics )
QVector< qreal > qskDashPattern( Qt::PenStyle style )
{ {
static QVector< qreal > pattern[] = static const QVector< qreal > pattern[] =
{ {
{}, { 1 }, { 4, 2 }, { 1, 2 }, {}, { 1 }, { 4, 2 }, { 1, 2 },
{ 4, 2, 1, 2 }, { 4, 2, 1, 2, 1, 2 }, {} { 4, 2, 1, 2 }, { 4, 2, 1, 2, 1, 2 }, {}
@ -29,7 +37,22 @@ static inline QVector< qreal > qskDashPattern( const Qt::PenStyle& style )
return pattern[ style ]; return pattern[ style ];
} }
Q_CONSTRUCTOR_FUNCTION( qskRegisterStippleMetrics ) static inline qreal qskInterpolated( qreal from, qreal to, qreal ratio )
{
return from + ( to - from ) * ratio;
}
static inline QVector< qreal > qskInterpolatedSpaces(
const QVector< qreal >& pattern, qreal progress )
{
QVector< qreal > interpolated;
interpolated.reserve( pattern.count() );
for ( int i = 1; i < pattern.count(); i += 2 )
interpolated[i] = progress * pattern[i];
return interpolated;
}
QskStippleMetrics::QskStippleMetrics( Qt::PenStyle penStyle ) QskStippleMetrics::QskStippleMetrics( Qt::PenStyle penStyle )
: m_pattern( qskDashPattern( penStyle ) ) : m_pattern( qskDashPattern( penStyle ) )
@ -56,6 +79,47 @@ void QskStippleMetrics::setOffset( qreal offset ) noexcept
m_offset = offset; m_offset = offset;
} }
QskStippleMetrics QskStippleMetrics::interpolated(
const QskStippleMetrics& to, qreal progress ) const
{
if ( *this == to )
return to;
const auto offset = qskInterpolated( m_offset, to.m_offset, progress );
QVector< qreal > pattern;
if ( isSolid() )
{
pattern = qskInterpolatedSpaces( to.m_pattern, progress );
}
else if ( to.isSolid() )
{
pattern = qskInterpolatedSpaces( m_pattern, 1.0 - progress );
}
else
{
const auto count = qMax( m_pattern.count(), to.m_pattern.count() );
pattern.reserve( count );
for ( int i = 0; i < count; i++ )
{
const auto v1 = m_pattern.value( i, 0.0 );
const auto v2 = to.m_pattern.value( i, 0.0 );
pattern += qskInterpolated( v1, v2, progress );
}
}
return QskStippleMetrics( pattern, offset );
}
QVariant QskStippleMetrics::interpolate(
const QskStippleMetrics& from, const QskStippleMetrics& to, qreal progress )
{
return QVariant::fromValue( from.interpolated( to, progress ) );
}
QskHashValue QskStippleMetrics::hash( QskHashValue seed ) const noexcept QskHashValue QskStippleMetrics::hash( QskHashValue seed ) const noexcept
{ {
auto hash = qHash( m_offset, seed ); auto hash = qHash( m_offset, seed );

View File

@ -38,6 +38,12 @@ class QSK_EXPORT QskStippleMetrics
void setPattern( const QVector< qreal >& ); void setPattern( const QVector< qreal >& );
QVector< qreal > pattern() const; QVector< qreal > pattern() const;
QskStippleMetrics interpolated(
const QskStippleMetrics&, qreal value ) const;
static QVariant interpolate( const QskStippleMetrics&,
const QskStippleMetrics&, qreal progress );
QskHashValue hash( QskHashValue seed = 0 ) const noexcept; QskHashValue hash( QskHashValue seed = 0 ) const noexcept;
private: private:
@ -85,6 +91,8 @@ inline bool QskStippleMetrics::isSolid() const noexcept
return m_pattern.count() == 1; return m_pattern.count() == 1;
} }
QSK_EXPORT QVector< qreal > qskDashPattern( Qt::PenStyle );
#ifndef QT_NO_DEBUG_STREAM #ifndef QT_NO_DEBUG_STREAM
class QDebug; class QDebug;

View File

@ -12,6 +12,7 @@
#include "QskBoxBorderMetrics.h" #include "QskBoxBorderMetrics.h"
#include "QskBoxBorderColors.h" #include "QskBoxBorderColors.h"
#include "QskShadowMetrics.h" #include "QskShadowMetrics.h"
#include "QskStippleMetrics.h"
#include "QskGraphic.h" #include "QskGraphic.h"
namespace namespace
@ -130,6 +131,11 @@ namespace
{ {
return aspect | QskAspect::Symbol; return aspect | QskAspect::Symbol;
} }
inline QskAspect aspectStipple( QskAspect aspect )
{
return aspect | QskAspect::Style;
}
} }
QskSkinHintTableEditor::QskSkinHintTableEditor( QskSkinHintTable* table ) QskSkinHintTableEditor::QskSkinHintTableEditor( QskSkinHintTable* table )
@ -583,8 +589,8 @@ void QskSkinHintTableEditor::setArcMetrics( QskAspect aspect,
setMetricHint( aspectShape( aspect ), arcMetrics, combination ); setMetricHint( aspectShape( aspect ), arcMetrics, combination );
} }
bool QskSkinHintTableEditor::removeArcMetrics( QskAspect aspect, bool QskSkinHintTableEditor::removeArcMetrics(
QskStateCombination combination ) QskAspect aspect, QskStateCombination combination )
{ {
return removeMetricHint( aspectShape( aspect ), combination ); return removeMetricHint( aspectShape( aspect ), combination );
} }
@ -594,6 +600,35 @@ QskArcMetrics QskSkinHintTableEditor::arcMetrics( QskAspect aspect ) const
return metricHint< QskArcMetrics >( aspectShape( aspect ) ); return metricHint< QskArcMetrics >( aspectShape( aspect ) );
} }
void QskSkinHintTableEditor::setStippleMetrics( QskAspect aspect,
Qt::PenStyle penStyle, QskStateCombination combination )
{
setStippleMetrics( aspect, QskStippleMetrics( penStyle ), combination );
}
void QskSkinHintTableEditor::setStippleMetrics( QskAspect aspect,
const QVector< qreal >& dashPattern, QskStateCombination combination )
{
setStippleMetrics( aspect, QskStippleMetrics( dashPattern ), combination );
}
void QskSkinHintTableEditor::setStippleMetrics( QskAspect aspect,
const QskStippleMetrics& metrics, QskStateCombination combination )
{
setMetricHint( aspectStipple( aspect ), metrics, combination );
}
bool QskSkinHintTableEditor::removeStippleMetrics(
QskAspect aspect, QskStateCombination combination )
{
return removeMetricHint( aspectStipple( aspect ), combination );
}
QskStippleMetrics QskSkinHintTableEditor::stippleMetrics( QskAspect aspect ) const
{
return metricHint< QskStippleMetrics >( aspectStipple( aspect ) );
}
void QskSkinHintTableEditor::setTextOptions( QskAspect aspect, void QskSkinHintTableEditor::setTextOptions( QskAspect aspect,
Qt::TextElideMode elideMode, QskTextOptions::WrapMode wrapMode, Qt::TextElideMode elideMode, QskTextOptions::WrapMode wrapMode,
QskStateCombination combination ) QskStateCombination combination )

View File

@ -14,6 +14,7 @@
#include <qcolor.h> #include <qcolor.h>
#include <qvariant.h> #include <qvariant.h>
#include <qvector.h>
class QskArcMetrics; class QskArcMetrics;
class QskMargins; class QskMargins;
@ -22,6 +23,7 @@ class QskBoxShapeMetrics;
class QskBoxBorderMetrics; class QskBoxBorderMetrics;
class QskBoxBorderColors; class QskBoxBorderColors;
class QskShadowMetrics; class QskShadowMetrics;
class QskStippleMetrics;
class QskGraphic; class QskGraphic;
class QSK_EXPORT QskSkinHintTableEditor class QSK_EXPORT QskSkinHintTableEditor
@ -265,6 +267,21 @@ class QSK_EXPORT QskSkinHintTableEditor
QskArcMetrics arcMetrics( QskAspect ) const; QskArcMetrics arcMetrics( QskAspect ) const;
// lines
void setStippleMetrics( QskAspect, Qt::PenStyle,
QskStateCombination = QskStateCombination() );
void setStippleMetrics( QskAspect, const QVector< qreal >&,
QskStateCombination = QskStateCombination() );
void setStippleMetrics( QskAspect, const QskStippleMetrics&,
QskStateCombination = QskStateCombination() );
bool removeStippleMetrics( QskAspect, QskStateCombination = QskStateCombination() );
QskStippleMetrics stippleMetrics( QskAspect ) const;
// text options flag // text options flag
void setTextOptions( QskAspect, void setTextOptions( QskAspect,

View File

@ -23,6 +23,7 @@
#include "QskBoxBorderMetrics.h" #include "QskBoxBorderMetrics.h"
#include "QskBoxBorderColors.h" #include "QskBoxBorderColors.h"
#include "QskShadowMetrics.h" #include "QskShadowMetrics.h"
#include "QskStippleMetrics.h"
#include "QskBoxHints.h" #include "QskBoxHints.h"
#include "QskGradient.h" #include "QskGradient.h"
#include "QskTextOptions.h" #include "QskTextOptions.h"
@ -638,6 +639,24 @@ QskArcMetrics QskSkinnable::arcMetricsHint(
this, aspect | QskAspect::Shape, status ); this, aspect | QskAspect::Shape, status );
} }
bool QskSkinnable::setStippleMetricsHint(
QskAspect aspect, const QskStippleMetrics& metrics )
{
return qskSetMetric( this, aspect | QskAspect::Style, metrics );
}
bool QskSkinnable::resetStippleMetricsHint( QskAspect aspect )
{
return resetMetric( aspect | QskAspect::Style );
}
QskStippleMetrics QskSkinnable::stippleMetricsHint(
QskAspect aspect, QskSkinHintStatus* status ) const
{
return qskMetric< QskStippleMetrics >(
this, aspect | QskAspect::Style, status );
}
bool QskSkinnable::setSpacingHint( const QskAspect aspect, qreal spacing ) bool QskSkinnable::setSpacingHint( const QskAspect aspect, qreal spacing )
{ {
return qskSetMetric( this, aspect | QskAspect::Spacing, spacing ); return qskSetMetric( this, aspect | QskAspect::Spacing, spacing );

View File

@ -30,6 +30,7 @@ class QskBoxShapeMetrics;
class QskBoxBorderMetrics; class QskBoxBorderMetrics;
class QskBoxBorderColors; class QskBoxBorderColors;
class QskShadowMetrics; class QskShadowMetrics;
class QskStippleMetrics;
class QskTextOptions; class QskTextOptions;
class QskBoxHints; class QskBoxHints;
class QskGradient; class QskGradient;
@ -228,6 +229,10 @@ class QSK_EXPORT QskSkinnable
bool resetArcMetricsHint( QskAspect ); bool resetArcMetricsHint( QskAspect );
QskArcMetrics arcMetricsHint( QskAspect, QskSkinHintStatus* = nullptr ) const; QskArcMetrics arcMetricsHint( QskAspect, QskSkinHintStatus* = nullptr ) const;
bool setStippleMetricsHint( QskAspect, const QskStippleMetrics& );
bool resetStippleMetricsHint( QskAspect );
QskStippleMetrics stippleMetricsHint( QskAspect, QskSkinHintStatus* = nullptr ) const;
bool setSpacingHint( QskAspect, qreal ); bool setSpacingHint( QskAspect, qreal );
bool resetSpacingHint( QskAspect ); bool resetSpacingHint( QskAspect );
qreal spacingHint( QskAspect, QskSkinHintStatus* = nullptr ) const; qreal spacingHint( QskAspect, QskSkinHintStatus* = nullptr ) const;

View File

@ -9,6 +9,7 @@
#include "QskBoxBorderMetrics.h" #include "QskBoxBorderMetrics.h"
#include "QskBoxShapeMetrics.h" #include "QskBoxShapeMetrics.h"
#include "QskShadowMetrics.h" #include "QskShadowMetrics.h"
#include "QskStippleMetrics.h"
#include "QskColorFilter.h" #include "QskColorFilter.h"
#include "QskGradient.h" #include "QskGradient.h"
#include "QskMargins.h" #include "QskMargins.h"
@ -46,6 +47,7 @@ static void qskRegisterInterpolator()
qRegisterAnimationInterpolator< QskBoxBorderColors >( QskBoxBorderColors::interpolate ); qRegisterAnimationInterpolator< QskBoxBorderColors >( QskBoxBorderColors::interpolate );
qRegisterAnimationInterpolator< QskTextColors >( QskTextColors::interpolate ); qRegisterAnimationInterpolator< QskTextColors >( QskTextColors::interpolate );
qRegisterAnimationInterpolator< QskShadowMetrics >( QskShadowMetrics::interpolate ); qRegisterAnimationInterpolator< QskShadowMetrics >( QskShadowMetrics::interpolate );
qRegisterAnimationInterpolator< QskStippleMetrics >( QskStippleMetrics::interpolate );
qRegisterAnimationInterpolator< QskArcMetrics >( QskArcMetrics::interpolate ); qRegisterAnimationInterpolator< QskArcMetrics >( QskArcMetrics::interpolate );
} }

View File

@ -0,0 +1,154 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskStippledLineRenderer.h"
QSK_QT_PRIVATE_BEGIN
#include <private/qstroker_p.h>
QSK_QT_PRIVATE_END
namespace
{
/*
Thanks to the hooks of the stroker classes we can make use
of QDashStroker without having to deal with the overhead of
QPainterPaths. But it might be worth to check if this could
be done in a shader. TODO ...
*/
class DashStroker : public QDashStroker
{
public:
DashStroker( QskStippledLineRenderer* renderer )
: QDashStroker( nullptr )
, m_renderer( renderer )
{
setDashOffset( renderer->metrics().offset() );
setDashPattern( renderer->metrics().pattern() );
m_elements.reserve( 2 );
}
void renderDashes( qreal x1, qreal y1, qreal x2, qreal y2 )
{
if ( ( x1 == x2 ) && ( y1 == y2 ) )
return;
setMoveToHook( moveTo );
setLineToHook( lineTo );
begin( this );
m_elements.add( { QPainterPath::MoveToElement, x1, y1 } );
m_elements.add( { QPainterPath::LineToElement, x2, y2 } );
processCurrentSubpath();
end();
}
qsizetype dashCount( qreal x1, qreal y1, qreal x2, qreal y2 )
{
if ( ( x1 == x2 ) && ( y1 == y2 ) )
return 0;
/*
There should be a faster way to calculate the
number of points. TODO ...
*/
setMoveToHook( countMoveTo );
setLineToHook( countLineTo );
m_count = 0;
begin( this );
m_elements.add( { QPainterPath::MoveToElement, x1, y1 } );
m_elements.add( { QPainterPath::LineToElement, x2, y2 } );
processCurrentSubpath();
end();
return m_count;
}
private:
static void moveTo( qfixed x, qfixed y, void* data )
{
auto stroker = reinterpret_cast< DashStroker* >( data );
stroker->m_x = x;
stroker->m_y = y;
}
static void lineTo( qfixed x, qfixed y, void* data )
{
auto stroker = reinterpret_cast< DashStroker* >( data );
stroker->m_renderer->renderDash( stroker->m_x, stroker->m_y, x, y );
}
static void countMoveTo( qfixed, qfixed, void* )
{
}
static void countLineTo( qfixed, qfixed, void* data )
{
auto stroker = reinterpret_cast< DashStroker* >( data );
stroker->m_count++;
}
QskStippledLineRenderer* m_renderer;
qsizetype m_count = 0;
qreal m_x, m_y;
};
}
QskStippledLineRenderer::QskStippledLineRenderer( const QskStippleMetrics& metrics )
: m_metrics( metrics )
{
}
QskStippledLineRenderer::~QskStippledLineRenderer()
{
}
qsizetype QskStippledLineRenderer::dashCount(
const QPointF& p1, const QPointF& p2 ) const
{
return dashCount( p1.x(), p1.y(), p2.x(), p2.y() );
}
qsizetype QskStippledLineRenderer::dashCount( const QLineF& line ) const
{
return dashCount( line.x1(), line.y1(), line.x2(), line.y2() );
}
qsizetype QskStippledLineRenderer::dashCount(
qreal x1, qreal y1, qreal x2, qreal y2 ) const
{
auto that = const_cast< QskStippledLineRenderer* >( this );
return DashStroker( that ).dashCount( x1, y1, x2, y2 );
}
void QskStippledLineRenderer::renderLine( const QPointF& p1, const QPointF& p2 )
{
renderLine( p1.x(), p1.y(), p2.x(), p2.y() );
}
void QskStippledLineRenderer::renderLine( const QLineF& line )
{
renderLine( line.x1(), line.y1(), line.x2(), line.y2() );
}
void QskStippledLineRenderer::renderLine( qreal x1, qreal y1, qreal x2, qreal y2 )
{
DashStroker( this ).renderDashes( x1, y1, x2, y2 );
}
void QskStippledLineRenderer::renderDash( qreal, qreal, qreal, qreal )
{
// nop
}

View File

@ -0,0 +1,47 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_STIPPLED_LINE_RENDERER_H
#define QSK_STIPPLED_LINE_RENDERER_H
#include "QskStippleMetrics.h"
class QLineF;
class QPointF;
/*
A wrapper for the non public QDashStroker class, tailored for
splitting lines into dashes/dots. It is faster than QPainterPathStroker
( no QPainterPath involved ), but supports simple lines only.
*/
class QskStippledLineRenderer
{
public:
QskStippledLineRenderer( const QskStippleMetrics& );
virtual ~QskStippledLineRenderer();
qsizetype dashCount( qreal x1, qreal y1, qreal x2, qreal y2 ) const;
qsizetype dashCount( const QPointF&, const QPointF& ) const;
qsizetype dashCount( const QLineF& ) const;
void renderLine( qreal x1, qreal y1, qreal x2, qreal y2 );
void renderLine( const QPointF&, const QPointF& );
void renderLine( const QLineF& );
const QskStippleMetrics& metrics() const;
// nop: to be overloaded
virtual void renderDash( qreal x1, qreal y1, qreal x2, qreal y2 );
private:
const QskStippleMetrics m_metrics;
};
inline const QskStippleMetrics& QskStippledLineRenderer::metrics() const
{
return m_metrics;
}
#endif