From bf19d6464c68f02d1abb8cca418e6a8f8f5b8e02 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 17 May 2023 14:21:40 +0200 Subject: [PATCH 01/29] QskLinesNode introduced --- src/CMakeLists.txt | 4 + src/common/QskStippleMetrics.cpp | 83 ++++++++ src/common/QskStippleMetrics.h | 97 +++++++++ src/nodes/QskLinesNode.cpp | 327 +++++++++++++++++++++++++++++++ src/nodes/QskLinesNode.h | 52 +++++ src/nodes/QskStrokeNode.cpp | 2 + src/nodes/QskStrokeNode.h | 1 + 7 files changed, 566 insertions(+) create mode 100644 src/common/QskStippleMetrics.cpp create mode 100644 src/common/QskStippleMetrics.h create mode 100644 src/nodes/QskLinesNode.cpp create mode 100644 src/nodes/QskLinesNode.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8d8cf4e6..e9e18947 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,6 +32,7 @@ list(APPEND HEADERS common/QskShadowMetrics.h common/QskSizePolicy.h common/QskStateCombination.h + common/QskStippleMetrics.h common/QskTextColors.h common/QskTextOptions.h ) @@ -61,6 +62,7 @@ list(APPEND SOURCES common/QskScaleTickmarks.cpp common/QskShadowMetrics.cpp common/QskSizePolicy.cpp + common/QskStippleMetrics.cpp common/QskTextColors.cpp common/QskTextOptions.cpp ) @@ -107,6 +109,7 @@ list(APPEND HEADERS nodes/QskBoxShadowNode.h nodes/QskColorRamp.h nodes/QskGraphicNode.h + nodes/QskLinesNode.h nodes/QskPaintedNode.h nodes/QskPlainTextRenderer.h nodes/QskRichTextRenderer.h @@ -135,6 +138,7 @@ list(APPEND SOURCES nodes/QskBoxShadowNode.cpp nodes/QskColorRamp.cpp nodes/QskGraphicNode.cpp + nodes/QskLinesNode.cpp nodes/QskPaintedNode.cpp nodes/QskPlainTextRenderer.cpp nodes/QskRectangleNode.cpp diff --git a/src/common/QskStippleMetrics.cpp b/src/common/QskStippleMetrics.cpp new file mode 100644 index 00000000..7bee7e54 --- /dev/null +++ b/src/common/QskStippleMetrics.cpp @@ -0,0 +1,83 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskStippleMetrics.h" + +#include +#include +#include + +static void qskRegisterStippleMetrics() +{ + qRegisterMetaType< QskStippleMetrics >(); + +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + QMetaType::registerEqualsComparator< QskStippleMetrics >(); +#endif +} + +static inline QVector< qreal > qskDashPattern( const Qt::PenStyle& style ) +{ + static QVector< qreal > pattern[] = + { + {}, { 1 }, { 4, 2 }, { 1, 2 }, + { 4, 2, 1, 2 }, { 4, 2, 1, 2, 1, 2 }, {} + }; + + return pattern[ style ]; +} + +Q_CONSTRUCTOR_FUNCTION( qskRegisterStippleMetrics ) + +QskStippleMetrics::QskStippleMetrics( Qt::PenStyle penStyle ) + : m_pattern( qskDashPattern( penStyle ) ) +{ +} + +QskStippleMetrics::QskStippleMetrics( const QPen& pen ) + : QskStippleMetrics( pen.style() ) +{ + if ( pen.style() == Qt::CustomDashLine ) + { + m_offset = pen.dashOffset(); + m_pattern = pen.dashPattern(); + } +} + +void QskStippleMetrics::setPattern( const QVector< qreal >& pattern ) +{ + m_pattern = pattern; +} + +void QskStippleMetrics::setOffset( qreal offset ) noexcept +{ + m_offset = offset; +} + +QskHashValue QskStippleMetrics::hash( QskHashValue seed ) const noexcept +{ + auto hash = qHash( m_offset, seed ); + return qHash( m_pattern, hash ); +} + +#ifndef QT_NO_DEBUG_STREAM + +#include + +QDebug operator<<( QDebug debug, const QskStippleMetrics& metrics ) +{ + QDebugStateSaver saver( debug ); + debug.nospace(); + + debug << "QskStippleMetrics" << '('; + debug << metrics.offset() << ',' << metrics.pattern(); + debug << ')'; + + return debug; +} + +#endif + +#include "moc_QskStippleMetrics.cpp" diff --git a/src/common/QskStippleMetrics.h b/src/common/QskStippleMetrics.h new file mode 100644 index 00000000..5029b0d9 --- /dev/null +++ b/src/common/QskStippleMetrics.h @@ -0,0 +1,97 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#ifndef QSK_STIPPLE_METRICS_H +#define QSK_STIPPLE_METRICS_H + +#include "QskGlobal.h" + +#include +#include +#include + +class QPen; + +class QSK_EXPORT QskStippleMetrics +{ + Q_GADGET + + Q_PROPERTY( qreal offset READ offset WRITE setOffset ) + Q_PROPERTY( QVector< qreal > pattern READ pattern WRITE setPattern ) + + public: + QskStippleMetrics( Qt::PenStyle = Qt::SolidLine ); + QskStippleMetrics( const QPen& ); + QskStippleMetrics( const QVector< qreal >&, qreal offset = 0.0 ); + + bool operator==( const QskStippleMetrics& ) const noexcept; + bool operator!=( const QskStippleMetrics& ) const noexcept; + + bool isValid() const noexcept; + bool isSolid() const noexcept; + + void setOffset( qreal offset ) noexcept; + qreal offset() const noexcept; + + void setPattern( const QVector< qreal >& ); + QVector< qreal > pattern() const; + + QskHashValue hash( QskHashValue seed = 0 ) const noexcept; + + private: + qreal m_offset = 0.0; + QVector< qreal > m_pattern; +}; + +inline QskStippleMetrics::QskStippleMetrics( + const QVector< qreal >& pattern, qreal offset ) + : m_offset( offset ) + , m_pattern( pattern ) +{ +} + +inline qreal QskStippleMetrics::offset() const noexcept +{ + return m_offset; +} + +inline QVector< qreal > QskStippleMetrics::pattern() const +{ + return m_pattern; +} + +inline bool QskStippleMetrics::operator==( + const QskStippleMetrics& other ) const noexcept +{ + return ( m_offset == other.m_offset ) + && ( m_pattern == other.m_pattern ); +} + +inline bool QskStippleMetrics::operator!=( + const QskStippleMetrics& other ) const noexcept +{ + return !( *this == other ); +} + +inline bool QskStippleMetrics::isValid() const noexcept +{ + return !m_pattern.isEmpty(); +} + +inline bool QskStippleMetrics::isSolid() const noexcept +{ + return m_pattern.count() == 1; +} + +#ifndef QT_NO_DEBUG_STREAM + +class QDebug; +QSK_EXPORT QDebug operator<<( QDebug, const QskStippleMetrics& ); + +#endif + +Q_DECLARE_METATYPE( QskStippleMetrics ) + +#endif diff --git a/src/nodes/QskLinesNode.cpp b/src/nodes/QskLinesNode.cpp new file mode 100644 index 00000000..29c0000f --- /dev/null +++ b/src/nodes/QskLinesNode.cpp @@ -0,0 +1,327 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskLinesNode.h" +#include "QskIntervalF.h" +#include "QskVertex.h" +#include "QskStippleMetrics.h" +#include "QskSGNode.h" + +#include +#include +#include +#include +#include + +QSK_QT_PRIVATE_BEGIN +#include +#include +QSK_QT_PRIVATE_END + +namespace +{ + inline qreal mapX( const QTransform& t, qreal x ) + { + return t.dx() + t.m11() * x; + } + + inline qreal mapY( const QTransform& t, qreal y ) + { + return t.dy() + t.m22() * y; + } + + /* + 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( const QskStippleMetrics& metrics ) + : QDashStroker( nullptr ) + { + setDashOffset( metrics.offset() ); + setDashPattern( metrics.pattern() ); + + m_elements.reserve( 2 ); + } + + QSGGeometry::Point2D* addDashes( QSGGeometry::Point2D* points, + qreal x1, qreal y1, qreal x2, qreal y2 ) + { + setMoveToHook( addPoint ); + setLineToHook( addPoint ); + + m_points = points; + + begin( this ); + + m_elements.add( { QPainterPath::MoveToElement, x1, y1 } ); + m_elements.add( { QPainterPath::LineToElement, x2, y2 } ); + + processCurrentSubpath(); + + end(); + + return m_points; + } + + int pointCount( qreal x1, qreal y1, qreal x2, qreal y2 ) + { + /* + There should be a faster way to calculate the + number of points. TODO ... + */ + setMoveToHook( countPoint ); + setLineToHook( countPoint ); + + 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 addPoint( qfixed x, qfixed y, void* data ) + { + auto stroker = reinterpret_cast< DashStroker* >( data ); + ( stroker->m_points++ )->set( x, y ); + } + + static void countPoint( qfixed, qfixed, void* data ) + { + auto stroker = reinterpret_cast< DashStroker* >( data ); + stroker->m_count++; + } + + int m_count = 0; + QSGGeometry::Point2D* m_points; + }; +} + +class QskLinesNodePrivate final : public QSGGeometryNodePrivate +{ + public: + QskLinesNodePrivate() + : geometry( QSGGeometry::defaultAttributes_Point2D(), 0 ) + { + geometry.setDrawingMode( QSGGeometry::DrawLines ); + geometry.setVertexDataPattern( QSGGeometry::StaticPattern ); + } + + inline qreal round( bool isHorizontal, qreal v ) const + { + const auto r2 = 2.0 * devicePixelRatio; + const qreal v0 = isHorizontal ? p0.x() : p0.y(); + + const int d = qRound( r2 * ( v + v0 ) ); + const auto f = ( d % 2 ? d : d - 1 ) / r2; + + return f / devicePixelRatio - v0; + } + + QSGGeometry geometry; + QSGFlatColorMaterial material; + + // position of [0,0] in device coordinates + QPointF p0; + qreal devicePixelRatio = 1.0; + + QskHashValue hash = 0.0; + bool dirty = true; +}; + +QskLinesNode::QskLinesNode() + : QSGGeometryNode( *new QskLinesNodePrivate ) +{ + Q_D( QskLinesNode ); + + setGeometry( &d->geometry ); + setMaterial( &d->material ); +} + +QskLinesNode::~QskLinesNode() +{ +} + +void QskLinesNode::setGlobalPosition( const QQuickItem* item ) +{ + QPointF p0; + qreal devicePixelRatio = 1.0; + + if ( item ) + { + p0 = item->mapToGlobal( QPointF() ); + + if ( auto w = item->window() ) + devicePixelRatio = w->devicePixelRatio(); + } + + setGlobalPosition( p0, devicePixelRatio ); +} + +void QskLinesNode::setGlobalPosition( + const QPointF& pos, qreal devicePixelRatio ) +{ + Q_D( QskLinesNode ); + + if ( pos != d->p0 || devicePixelRatio != d->devicePixelRatio ) + { + d->p0 = pos; + d->devicePixelRatio = devicePixelRatio; + + d->dirty = true; + } +} + +void QskLinesNode::updateGrid( const QColor& color, qreal lineWidth, + const QskStippleMetrics& stippleMetrics, const QTransform& transform, + const QskIntervalF& xBoundaries, const QVector< qreal >& xValues, + const QskIntervalF& yBoundaries, const QVector< qreal >& yValues ) +{ + Q_D( QskLinesNode ); + + if ( color != d->material.color() ) + { + d->material.setColor( color ); + markDirty( QSGNode::DirtyMaterial ); + } + + QskHashValue hash = 9784; + + hash = stippleMetrics.hash( hash ); + hash = qHash( transform, hash ); + hash = qHashBits( &xBoundaries, sizeof( xBoundaries ), hash ); + hash = qHashBits( &yBoundaries, sizeof( yBoundaries ), hash ); + hash = qHash( xValues, hash ); + hash = qHash( yValues, hash ); + + if ( hash != d->hash ) + { + d->dirty = true; + d->hash = hash; + } + + if( d->dirty ) + { + if ( !( stippleMetrics.isValid() + && color.isValid() && color.alpha() > 0 ) ) + { + QskSGNode::resetGeometry( this ); + } + else + { + updateGeometry( stippleMetrics, transform, + xBoundaries, xValues, yBoundaries, yValues ); + } + + markDirty( QSGNode::DirtyGeometry ); + d->dirty = false; + } + + const float lineWidthF = lineWidth; + if( lineWidthF != d->geometry.lineWidth() ) + d->geometry.setLineWidth( lineWidthF ); +} + +void QskLinesNode::updateGeometry( + const QskStippleMetrics& stippleMetrics, const QTransform& transform, + const QskIntervalF& xBoundaries, const QVector< qreal >& xValues, + const QskIntervalF& yBoundaries, const QVector< qreal >& yValues ) +{ + Q_D( QskLinesNode ); + + const auto x1 = mapX( transform, xBoundaries.lowerBound() ); + const auto x2 = mapX( transform, xBoundaries.upperBound() ); + + const auto y1 = mapY( transform, yBoundaries.lowerBound() ); + const auto y2 = mapY( transform, yBoundaries.upperBound() ); + + if ( stippleMetrics.isSolid() ) + { + using namespace QskVertex; + + auto lines = allocateLines< Line >( + d->geometry, xValues.count() + yValues.count() ); + + for ( auto x : xValues ) + { + x = mapX( transform, x ); + x = d->round( true, x ); + + lines++->setVLine( x, y1, y2 ); + } + + for ( auto y : yValues ) + { + y = mapY( transform, y ); + y = d->round( false, y ); + + lines++->setHLine( x1, x2, y ); + } + } + else + { + DashStroker stroker( stippleMetrics ); + + const int countX = stroker.pointCount( 0.0, y1, 0.0, y2 ); + const int countY = stroker.pointCount( x1, 0.0, x2, 0.0 ); + + auto count = xValues.count() * countX + yValues.count() * countY; + + d->geometry.allocate( count ); + auto points = d->geometry.vertexDataAsPoint2D(); + + /* + We have to calculate the first line only. All others are + translation without changing the positions of the dashes. + */ + auto p0 = points; + + for ( int i = 0; i < xValues.count(); i++ ) + { + auto x = mapX( transform, xValues[i] ); + x = d->round( true, x ); + + if ( i == 0 ) + { + points = stroker.addDashes( points, x, y1, x, y2 ); + } + else + { + for ( int j = 0; j < countX; j++ ) + points++->set( x, p0[j].y ); + } + } + + p0 = points; + + for ( int i = 0; i < yValues.count(); i++ ) + { + auto y = mapY( transform, yValues[i] ); + y = d->round( false, y ); + + if ( i == 0 ) + { + points = stroker.addDashes( points, x1, y, x2, y ); + } + else + { + for ( int j = 0; j < countY; j++ ) + points++->set( p0[j].x, y ); + } + } + } +} diff --git a/src/nodes/QskLinesNode.h b/src/nodes/QskLinesNode.h new file mode 100644 index 00000000..d52c4ba1 --- /dev/null +++ b/src/nodes/QskLinesNode.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#ifndef QSK_LINES_NODE_H +#define QSK_LINES_NODE_H + +#include "QskGlobal.h" + +#include +#include + +class QskIntervalF; +class QskStippleMetrics; +class QTransform; +class QPointF; +class QQuickItem; + +class QskLinesNodePrivate; + +/* + A node for stippled or solid lines. + For the moment limited to horizontal/vertical lines: TODO + */ +class QSK_EXPORT QskLinesNode : public QSGGeometryNode +{ + public: + QskLinesNode(); + ~QskLinesNode() override; + + void setGlobalPosition( const QPointF&, qreal devicePixelRatio ); + void setGlobalPosition( const QQuickItem* ); + + void setLineColor( const QColor& ); + void setLineWidth( qreal ); + + void updateGrid( const QColor&, qreal lineWidth, + const QskStippleMetrics&, const QTransform&, + const QskIntervalF&, const QVector< qreal >&, + const QskIntervalF&, const QVector< qreal >& ); + + private: + void updateGeometry( + const QskStippleMetrics&, const QTransform&, + const QskIntervalF&, const QVector< qreal >&, + const QskIntervalF&, const QVector< qreal >& ); + + Q_DECLARE_PRIVATE( QskLinesNode ) +}; + +#endif diff --git a/src/nodes/QskStrokeNode.cpp b/src/nodes/QskStrokeNode.cpp index 588ce62a..b58d5208 100644 --- a/src/nodes/QskStrokeNode.cpp +++ b/src/nodes/QskStrokeNode.cpp @@ -86,6 +86,8 @@ QskStrokeNode::QskStrokeNode() setMaterial( qskMaterialColorVertex ); } +QskStrokeNode::~QskStrokeNode() = default; + void QskStrokeNode::setRenderHint( RenderHint renderHint ) { Q_D( QskStrokeNode ); diff --git a/src/nodes/QskStrokeNode.h b/src/nodes/QskStrokeNode.h index 9f212e75..31e8a446 100644 --- a/src/nodes/QskStrokeNode.h +++ b/src/nodes/QskStrokeNode.h @@ -19,6 +19,7 @@ class QSK_EXPORT QskStrokeNode : public QSGGeometryNode { public: QskStrokeNode(); + ~QskStrokeNode() override; /* We only support monochrome pens ( QPen::color() ) and using a From 5d3cba5650ea69f39cfab829d5b0cb42e4664bc0 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 17 May 2023 16:46:25 +0200 Subject: [PATCH 02/29] QskLinesNode reorganized --- src/nodes/QskLinesNode.cpp | 209 ++++++++++++++++++++++++------------- src/nodes/QskLinesNode.h | 26 +++-- 2 files changed, 155 insertions(+), 80 deletions(-) diff --git a/src/nodes/QskLinesNode.cpp b/src/nodes/QskLinesNode.cpp index 29c0000f..3774963d 100644 --- a/src/nodes/QskLinesNode.cpp +++ b/src/nodes/QskLinesNode.cpp @@ -4,7 +4,6 @@ *****************************************************************************/ #include "QskLinesNode.h" -#include "QskIntervalF.h" #include "QskVertex.h" #include "QskStippleMetrics.h" #include "QskSGNode.h" @@ -186,10 +185,19 @@ void QskLinesNode::setGlobalPosition( } } -void QskLinesNode::updateGrid( const QColor& color, qreal lineWidth, - const QskStippleMetrics& stippleMetrics, const QTransform& transform, - const QskIntervalF& xBoundaries, const QVector< qreal >& xValues, - const QskIntervalF& yBoundaries, const QVector< qreal >& yValues ) +void QskLinesNode::updateLines( const QColor& color, + qreal lineWidth, const QskStippleMetrics& stippleMetrics, + const QTransform& transform, const QRectF& rect ) +{ + // using QVarLengthArray instead. TODO ... + updateLines( color, lineWidth, stippleMetrics, transform, + rect, { rect.left(), rect.right() }, { rect.top(), rect.bottom() } ); +} + +void QskLinesNode::updateLines( const QColor& color, + qreal lineWidth, const QskStippleMetrics& stippleMetrics, + const QTransform& transform, const QRectF& rect, + const QVector< qreal >& xValues, const QVector< qreal >& yValues ) { Q_D( QskLinesNode ); @@ -203,8 +211,7 @@ void QskLinesNode::updateGrid( const QColor& color, qreal lineWidth, hash = stippleMetrics.hash( hash ); hash = qHash( transform, hash ); - hash = qHashBits( &xBoundaries, sizeof( xBoundaries ), hash ); - hash = qHashBits( &yBoundaries, sizeof( yBoundaries ), hash ); + hash = qHashBits( &rect, sizeof( QRectF ), hash ); hash = qHash( xValues, hash ); hash = qHash( yValues, hash ); @@ -216,15 +223,15 @@ void QskLinesNode::updateGrid( const QColor& color, qreal lineWidth, if( d->dirty ) { - if ( !( stippleMetrics.isValid() - && color.isValid() && color.alpha() > 0 ) ) + if ( rect.isEmpty() || !stippleMetrics.isValid() + || !color.isValid() || color.alpha() == 0 ) { QskSGNode::resetGeometry( this ); } else { - updateGeometry( stippleMetrics, transform, - xBoundaries, xValues, yBoundaries, yValues ); + updateGeometry( stippleMetrics, + transform, rect, xValues, yValues ); } markDirty( QSGNode::DirtyGeometry ); @@ -237,40 +244,34 @@ void QskLinesNode::updateGrid( const QColor& color, qreal lineWidth, } void QskLinesNode::updateGeometry( - const QskStippleMetrics& stippleMetrics, const QTransform& transform, - const QskIntervalF& xBoundaries, const QVector< qreal >& xValues, - const QskIntervalF& yBoundaries, const QVector< qreal >& yValues ) + const QskStippleMetrics& stippleMetrics, + const QTransform& transform, const QRectF& rect, + const QVector< qreal >& xValues, const QVector< qreal >& yValues ) { Q_D( QskLinesNode ); - const auto x1 = mapX( transform, xBoundaries.lowerBound() ); - const auto x2 = mapX( transform, xBoundaries.upperBound() ); + auto& geom = d->geometry; - const auto y1 = mapY( transform, yBoundaries.lowerBound() ); - const auto y2 = mapY( transform, yBoundaries.upperBound() ); + const auto y1 = mapY( transform, rect.top() ); + const auto y2 = mapY( transform, rect.bottom() ); + + const auto x1 = mapX( transform, rect.left() ); + const auto x2 = mapX( transform, rect.right() ); + + QSGGeometry::Point2D* points = nullptr; if ( stippleMetrics.isSolid() ) { using namespace QskVertex; - auto lines = allocateLines< Line >( - d->geometry, xValues.count() + yValues.count() ); + geom.allocate( 2 * ( xValues.count() + yValues.count() ) ); + points = geom.vertexDataAsPoint2D(); - for ( auto x : xValues ) - { - x = mapX( transform, x ); - x = d->round( true, x ); + points = setSolidLines( Qt::Vertical, y1, y2, + transform, xValues.count(), xValues.constData(), points ); - lines++->setVLine( x, y1, y2 ); - } - - for ( auto y : yValues ) - { - y = mapY( transform, y ); - y = d->round( false, y ); - - lines++->setHLine( x1, x2, y ); - } + points = setSolidLines( Qt::Horizontal, x1, x2, + transform, yValues.count(), yValues.constData(), points ); } else { @@ -279,49 +280,115 @@ void QskLinesNode::updateGeometry( const int countX = stroker.pointCount( 0.0, y1, 0.0, y2 ); const int countY = stroker.pointCount( x1, 0.0, x2, 0.0 ); - auto count = xValues.count() * countX + yValues.count() * countY; + d->geometry.allocate( xValues.count() * countX + yValues.count() * countY ); + points = d->geometry.vertexDataAsPoint2D(); - d->geometry.allocate( count ); - auto points = d->geometry.vertexDataAsPoint2D(); + points = setStippledLines( Qt::Vertical, y1, y2, + transform, xValues.count(), xValues.constData(), + stippleMetrics, points ); - /* - We have to calculate the first line only. All others are - translation without changing the positions of the dashes. - */ - auto p0 = points; + points = setStippledLines( Qt::Horizontal, x1, x2, + transform, yValues.count(), yValues.constData(), + stippleMetrics, points ); + } - for ( int i = 0; i < xValues.count(); i++ ) + Q_ASSERT( geom.vertexCount() == ( points - geom.vertexDataAsPoint2D() ) ); +} + +QSGGeometry::Point2D* QskLinesNode::setStippledLines( + Qt::Orientation orientation, qreal v1, qreal v2, + const QTransform& transform, int count, const qreal* values, + const QskStippleMetrics& stippleMetrics, QSGGeometry::Point2D* points ) const +{ + Q_D( const QskLinesNode ); + + if ( count <= 0 ) + return points; + + DashStroker stroker( stippleMetrics ); + + // Calculating the dashes for the first line + + const auto line0 = points; + int dashCount = 0; + + if ( orientation == Qt::Vertical ) + { + auto x = mapX( transform, values[0] ); + x = d->round( true, x ); + + points = stroker.addDashes( points, x, v1, x, v2 ); + dashCount = points - line0; + } + else + { + auto y = mapY( transform, values[0] ); + y = d->round( false, y ); + + points = stroker.addDashes( points, v1, y, v2, y ); + dashCount = points - line0; + } + + // all other dashes are translations of the dashes of the first line + + if ( orientation == Qt::Vertical ) + { + for ( int i = 1; i < count; i++ ) { - auto x = mapX( transform, xValues[i] ); + auto x = mapX( transform, values[i] ); x = d->round( true, x ); - if ( i == 0 ) - { - points = stroker.addDashes( points, x, y1, x, y2 ); - } - else - { - for ( int j = 0; j < countX; j++ ) - points++->set( x, p0[j].y ); - } - } - - p0 = points; - - for ( int i = 0; i < yValues.count(); i++ ) - { - auto y = mapY( transform, yValues[i] ); - y = d->round( false, y ); - - if ( i == 0 ) - { - points = stroker.addDashes( points, x1, y, x2, y ); - } - else - { - for ( int j = 0; j < countY; j++ ) - points++->set( p0[j].x, y ); - } + for ( int j = 0; j < dashCount; j++ ) + points++->set( x, line0[j].y ); } } + else + { + for ( int i = 1; i < count; i++ ) + { + auto y = mapY( transform, values[i] ); + y = d->round( false, y ); + + for ( int j = 0; j < dashCount; j++ ) + points++->set( line0[j].x, y ); + } + } + + return points; +} + +QSGGeometry::Point2D* QskLinesNode::setSolidLines( + Qt::Orientation orientation, qreal v1, qreal v2, + const QTransform& transform, int count, const qreal* values, + QSGGeometry::Point2D* points ) const +{ + Q_D( const QskLinesNode ); + + if ( count <= 0 ) + return points; + + auto lines = reinterpret_cast< QskVertex::Line* >( points ); + + if ( orientation == Qt::Vertical ) + { + for ( int i = 0; i < count; i++ ) + { + auto x = mapX( transform, values[i] ); + x = d->round( true, x ); + + lines++->setVLine( x, v1, v2 ); + } + } + else + { + for ( int i = 0; i < count; i++ ) + { + auto y = mapY( transform, values[i] ); + y = d->round( false, y ); + + lines++->setHLine( v1, v2, y ); + } + } + + return reinterpret_cast< QSGGeometry::Point2D* >( lines ); } diff --git a/src/nodes/QskLinesNode.h b/src/nodes/QskLinesNode.h index d52c4ba1..65d1f544 100644 --- a/src/nodes/QskLinesNode.h +++ b/src/nodes/QskLinesNode.h @@ -32,19 +32,27 @@ class QSK_EXPORT QskLinesNode : public QSGGeometryNode void setGlobalPosition( const QPointF&, qreal devicePixelRatio ); void setGlobalPosition( const QQuickItem* ); - void setLineColor( const QColor& ); - void setLineWidth( qreal ); + void updateLines( const QColor&, qreal lineWidth, + const QskStippleMetrics&, const QTransform&, const QRectF&, + const QVector< qreal >&, const QVector< qreal >& ); - void updateGrid( const QColor&, qreal lineWidth, - const QskStippleMetrics&, const QTransform&, - const QskIntervalF&, const QVector< qreal >&, - const QskIntervalF&, const QVector< qreal >& ); + void updateLines( const QColor&, qreal lineWidth, + const QskStippleMetrics&, const QTransform&, const QRectF& ); private: void updateGeometry( - const QskStippleMetrics&, const QTransform&, - const QskIntervalF&, const QVector< qreal >&, - const QskIntervalF&, const QVector< qreal >& ); + const QskStippleMetrics&, const QTransform&, const QRectF&, + const QVector< qreal >&, const QVector< qreal >& ); + + QSGGeometry::Point2D* setSolidLines( + Qt::Orientation, qreal, qreal, + const QTransform&, int count, const qreal* values, + QSGGeometry::Point2D* ) const; + + QSGGeometry::Point2D* setStippledLines( + Qt::Orientation, qreal, qreal, + const QTransform&, int count, const qreal* values, + const QskStippleMetrics&, QSGGeometry::Point2D* ) const; Q_DECLARE_PRIVATE( QskLinesNode ) }; From d84e75a3d1bd8cb1e8733d7ead5b7c21dfc99345 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Thu, 25 May 2023 14:52:54 +0200 Subject: [PATCH 03/29] implementation of QskStippleMetrics completed --- src/CMakeLists.txt | 2 + src/common/QskStippleMetrics.cpp | 70 ++++++++++- src/common/QskStippleMetrics.h | 8 ++ src/controls/QskSkinHintTableEditor.cpp | 39 +++++- src/controls/QskSkinHintTableEditor.h | 17 +++ src/controls/QskSkinnable.cpp | 19 +++ src/controls/QskSkinnable.h | 5 + src/controls/QskVariantAnimator.cpp | 2 + src/nodes/QskStippledLineRenderer.cpp | 154 ++++++++++++++++++++++++ src/nodes/QskStippledLineRenderer.h | 47 ++++++++ 10 files changed, 358 insertions(+), 5 deletions(-) create mode 100644 src/nodes/QskStippledLineRenderer.cpp create mode 100644 src/nodes/QskStippledLineRenderer.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e9e18947..07b1b761 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,6 +116,7 @@ list(APPEND HEADERS nodes/QskScaleRenderer.h nodes/QskSGNode.h nodes/QskStrokeNode.h + nodes/QskStippledLineRenderer.h nodes/QskShapeNode.h nodes/QskGradientMaterial.h nodes/QskTextNode.h @@ -146,6 +147,7 @@ list(APPEND SOURCES nodes/QskScaleRenderer.cpp nodes/QskSGNode.cpp nodes/QskStrokeNode.cpp + nodes/QskStippledLineRenderer.cpp nodes/QskShapeNode.cpp nodes/QskGradientMaterial.cpp nodes/QskTextNode.cpp diff --git a/src/common/QskStippleMetrics.cpp b/src/common/QskStippleMetrics.cpp index 7bee7e54..6b4d0520 100644 --- a/src/common/QskStippleMetrics.cpp +++ b/src/common/QskStippleMetrics.cpp @@ -16,11 +16,19 @@ static void qskRegisterStippleMetrics() #if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) QMetaType::registerEqualsComparator< QskStippleMetrics >(); #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 }, { 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 ]; } -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 ) : m_pattern( qskDashPattern( penStyle ) ) @@ -56,6 +79,47 @@ void QskStippleMetrics::setOffset( qreal offset ) noexcept 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 { auto hash = qHash( m_offset, seed ); diff --git a/src/common/QskStippleMetrics.h b/src/common/QskStippleMetrics.h index 5029b0d9..a637faf1 100644 --- a/src/common/QskStippleMetrics.h +++ b/src/common/QskStippleMetrics.h @@ -38,6 +38,12 @@ class QSK_EXPORT QskStippleMetrics void setPattern( const QVector< qreal >& ); 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; private: @@ -85,6 +91,8 @@ inline bool QskStippleMetrics::isSolid() const noexcept return m_pattern.count() == 1; } +QSK_EXPORT QVector< qreal > qskDashPattern( Qt::PenStyle ); + #ifndef QT_NO_DEBUG_STREAM class QDebug; diff --git a/src/controls/QskSkinHintTableEditor.cpp b/src/controls/QskSkinHintTableEditor.cpp index 99f402ea..7e5e9199 100644 --- a/src/controls/QskSkinHintTableEditor.cpp +++ b/src/controls/QskSkinHintTableEditor.cpp @@ -12,6 +12,7 @@ #include "QskBoxBorderMetrics.h" #include "QskBoxBorderColors.h" #include "QskShadowMetrics.h" +#include "QskStippleMetrics.h" #include "QskGraphic.h" namespace @@ -130,6 +131,11 @@ namespace { return aspect | QskAspect::Symbol; } + + inline QskAspect aspectStipple( QskAspect aspect ) + { + return aspect | QskAspect::Style; + } } QskSkinHintTableEditor::QskSkinHintTableEditor( QskSkinHintTable* table ) @@ -583,8 +589,8 @@ void QskSkinHintTableEditor::setArcMetrics( QskAspect aspect, setMetricHint( aspectShape( aspect ), arcMetrics, combination ); } -bool QskSkinHintTableEditor::removeArcMetrics( QskAspect aspect, - QskStateCombination combination ) +bool QskSkinHintTableEditor::removeArcMetrics( + QskAspect aspect, QskStateCombination combination ) { return removeMetricHint( aspectShape( aspect ), combination ); } @@ -594,6 +600,35 @@ QskArcMetrics QskSkinHintTableEditor::arcMetrics( QskAspect aspect ) const 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, Qt::TextElideMode elideMode, QskTextOptions::WrapMode wrapMode, QskStateCombination combination ) diff --git a/src/controls/QskSkinHintTableEditor.h b/src/controls/QskSkinHintTableEditor.h index 10565b81..db3e7f6c 100644 --- a/src/controls/QskSkinHintTableEditor.h +++ b/src/controls/QskSkinHintTableEditor.h @@ -14,6 +14,7 @@ #include #include +#include class QskArcMetrics; class QskMargins; @@ -22,6 +23,7 @@ class QskBoxShapeMetrics; class QskBoxBorderMetrics; class QskBoxBorderColors; class QskShadowMetrics; +class QskStippleMetrics; class QskGraphic; class QSK_EXPORT QskSkinHintTableEditor @@ -265,6 +267,21 @@ class QSK_EXPORT QskSkinHintTableEditor 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 void setTextOptions( QskAspect, diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index f3d273cb..5b6421b4 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -23,6 +23,7 @@ #include "QskBoxBorderMetrics.h" #include "QskBoxBorderColors.h" #include "QskShadowMetrics.h" +#include "QskStippleMetrics.h" #include "QskBoxHints.h" #include "QskGradient.h" #include "QskTextOptions.h" @@ -638,6 +639,24 @@ QskArcMetrics QskSkinnable::arcMetricsHint( 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 ) { return qskSetMetric( this, aspect | QskAspect::Spacing, spacing ); diff --git a/src/controls/QskSkinnable.h b/src/controls/QskSkinnable.h index 3a736a83..2f28091c 100644 --- a/src/controls/QskSkinnable.h +++ b/src/controls/QskSkinnable.h @@ -30,6 +30,7 @@ class QskBoxShapeMetrics; class QskBoxBorderMetrics; class QskBoxBorderColors; class QskShadowMetrics; +class QskStippleMetrics; class QskTextOptions; class QskBoxHints; class QskGradient; @@ -228,6 +229,10 @@ class QSK_EXPORT QskSkinnable bool resetArcMetricsHint( QskAspect ); 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 resetSpacingHint( QskAspect ); qreal spacingHint( QskAspect, QskSkinHintStatus* = nullptr ) const; diff --git a/src/controls/QskVariantAnimator.cpp b/src/controls/QskVariantAnimator.cpp index 2c7c54df..dc196772 100644 --- a/src/controls/QskVariantAnimator.cpp +++ b/src/controls/QskVariantAnimator.cpp @@ -9,6 +9,7 @@ #include "QskBoxBorderMetrics.h" #include "QskBoxShapeMetrics.h" #include "QskShadowMetrics.h" +#include "QskStippleMetrics.h" #include "QskColorFilter.h" #include "QskGradient.h" #include "QskMargins.h" @@ -46,6 +47,7 @@ static void qskRegisterInterpolator() qRegisterAnimationInterpolator< QskBoxBorderColors >( QskBoxBorderColors::interpolate ); qRegisterAnimationInterpolator< QskTextColors >( QskTextColors::interpolate ); qRegisterAnimationInterpolator< QskShadowMetrics >( QskShadowMetrics::interpolate ); + qRegisterAnimationInterpolator< QskStippleMetrics >( QskStippleMetrics::interpolate ); qRegisterAnimationInterpolator< QskArcMetrics >( QskArcMetrics::interpolate ); } diff --git a/src/nodes/QskStippledLineRenderer.cpp b/src/nodes/QskStippledLineRenderer.cpp new file mode 100644 index 00000000..f578f478 --- /dev/null +++ b/src/nodes/QskStippledLineRenderer.cpp @@ -0,0 +1,154 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskStippledLineRenderer.h" + +QSK_QT_PRIVATE_BEGIN +#include +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 +} diff --git a/src/nodes/QskStippledLineRenderer.h b/src/nodes/QskStippledLineRenderer.h new file mode 100644 index 00000000..acda0bb7 --- /dev/null +++ b/src/nodes/QskStippledLineRenderer.h @@ -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 From bf74b4edf1666411e5def0e70d3df394e33b8b80 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Thu, 25 May 2023 14:54:18 +0200 Subject: [PATCH 04/29] using '*.h' includes --- src/controls/QskSegmentedBar.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controls/QskSegmentedBar.cpp b/src/controls/QskSegmentedBar.cpp index 32c0b93d..0dc68537 100644 --- a/src/controls/QskSegmentedBar.cpp +++ b/src/controls/QskSegmentedBar.cpp @@ -11,9 +11,9 @@ #include "QskSkinlet.h" #include "QskAspect.h" -#include -#include -#include +#include +#include +#include QSK_SUBCONTROL( QskSegmentedBar, Panel ) QSK_SUBCONTROL( QskSegmentedBar, Segment ) From 90388699094046ff3d26e3432c947e8b4abb59ec Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Thu, 25 May 2023 14:56:54 +0200 Subject: [PATCH 05/29] effectiveFont allows qualified aspects now --- src/controls/QskSkinnable.cpp | 8 ++++---- src/controls/QskSkinnable.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index 5b6421b4..beb63889 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -708,14 +708,14 @@ int QskSkinnable::fontRoleHint( return qskFlag( this, aspect | QskAspect::FontRole, status ); } -QFont QskSkinnable::effectiveFont( const QskAspect::Subcontrol subControl ) const +QFont QskSkinnable::effectiveFont( const QskAspect aspect ) const { - return effectiveSkin()->font( fontRoleHint( subControl ) ); + return effectiveSkin()->font( fontRoleHint( aspect ) ); } -qreal QskSkinnable::effectiveFontHeight( const QskAspect::Subcontrol subControl ) const +qreal QskSkinnable::effectiveFontHeight( const QskAspect aspect ) const { - const QFontMetricsF fm( effectiveFont( subControl ) ); + const QFontMetricsF fm( effectiveFont( aspect ) ); return fm.height(); } diff --git a/src/controls/QskSkinnable.h b/src/controls/QskSkinnable.h index 2f28091c..91c860b9 100644 --- a/src/controls/QskSkinnable.h +++ b/src/controls/QskSkinnable.h @@ -82,8 +82,8 @@ class QSK_EXPORT QskSkinnable void setSkinlet( const QskSkinlet* ); const QskSkinlet* skinlet() const; - QFont effectiveFont( QskAspect::Subcontrol ) const; - qreal effectiveFontHeight( QskAspect::Subcontrol ) const; + QFont effectiveFont( QskAspect ) const; + qreal effectiveFontHeight( QskAspect ) const; QskColorFilter effectiveGraphicFilter( QskAspect::Subcontrol ) const; void setSubcontrolProxy( QskAspect::Subcontrol, QskAspect::Subcontrol proxy ); From 3c62809308d3f4b6ad7b903bbed7498e1bc9e439 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Thu, 25 May 2023 14:58:37 +0200 Subject: [PATCH 06/29] exporting resetGeometry --- src/nodes/QskSGNode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nodes/QskSGNode.h b/src/nodes/QskSGNode.h index 95ac69a8..3ebe7e82 100644 --- a/src/nodes/QskSGNode.h +++ b/src/nodes/QskSGNode.h @@ -85,7 +85,7 @@ namespace QskSGNode return static_cast< Node* >( node ); } - void resetGeometry( QSGGeometryNode* ); + QSK_EXPORT void resetGeometry( QSGGeometryNode* ); } #endif From 587183993badfa84a262cd206c0d3f4b1f04f816 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Thu, 25 May 2023 15:03:48 +0200 Subject: [PATCH 07/29] QskLinesNode improvements --- src/controls/QskSkinlet.cpp | 79 ++++++++- src/controls/QskSkinlet.h | 6 + src/nodes/QskLinesNode.cpp | 309 ++++++++++++++++++++++++++---------- src/nodes/QskLinesNode.h | 19 ++- 4 files changed, 317 insertions(+), 96 deletions(-) diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index a8a194f5..b1e73ace 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -21,8 +21,10 @@ #include "QskGradient.h" #include "QskGraphicNode.h" #include "QskGraphic.h" +#include "QskLinesNode.h" #include "QskRectangleNode.h" #include "QskSGNode.h" +#include "QskStippleMetrics.h" #include "QskTextColors.h" #include "QskTextNode.h" #include "QskTextOptions.h" @@ -161,6 +163,11 @@ static inline bool qskIsArcVisible( const QskArcMetrics& arcMetrics, return gradient.isVisible(); } +static inline bool qskIsLineVisible( const QColor& lineColor, qreal lineWidth ) +{ + return ( lineWidth > 0.0 ) && lineColor.isValid() && ( lineColor.alpha() > 0 ); +} + static inline QskTextColors qskTextColors( const QskSkinnable* skinnable, QskAspect::Subcontrol subControl ) { @@ -199,13 +206,10 @@ static inline QSGNode* qskUpdateBoxNode( if ( qskIsBoxVisible( absoluteMetrics, borderColors, gradient ) ) { - auto boxNode = static_cast< QskBoxNode* >( node ); - if ( boxNode == nullptr ) - boxNode = new QskBoxNode(); - const auto absoluteShape = shape.toAbsolute( size ); const auto absoluteShadowMetrics = shadowMetrics.toAbsolute( size ); + auto boxNode = QskSGNode::ensureNode< QskBoxNode >( node ); boxNode->updateNode( rect, absoluteShape, absoluteMetrics, borderColors, gradient, absoluteShadowMetrics, shadowColor ); @@ -226,15 +230,46 @@ static inline QSGNode* qskUpdateArcNode( if ( !qskIsArcVisible( metrics, borderWidth, borderColor, gradient ) ) return nullptr; - auto arcNode = static_cast< QskArcNode* >( node ); - if ( arcNode == nullptr ) - arcNode = new QskArcNode(); - + auto arcNode = QskSGNode::ensureNode< QskArcNode >( node ); arcNode->setArcData( rect, metrics, borderWidth, borderColor, gradient ); return arcNode; } +static inline QSGNode* qskUpdateLineNode( + const QskSkinnable*, QSGNode* node, const QColor& lineColor, + qreal lineWidth, QskStippleMetrics& lineStipple, const QLineF& line ) +{ + if ( line.isNull() ) + return nullptr; + + if ( !qskIsLineVisible( lineColor, lineWidth ) ) + return nullptr; + + auto linesNode = QskSGNode::ensureNode< QskLinesNode >( node ); + linesNode->updateLine( lineColor, lineWidth, lineStipple, + QTransform(), line.p1(), line.p2() ); + + return linesNode; +} + +static inline QSGNode* qskUpdateLinesNode( + const QskSkinnable*, QSGNode* node, const QColor& lineColor, + qreal lineWidth, QskStippleMetrics& lineStipple, const QVector< QLineF >& lines ) +{ + if ( lines.isEmpty() ) + return nullptr; + + if ( !qskIsLineVisible( lineColor, lineWidth ) ) + return nullptr; + + auto linesNode = QskSGNode::ensureNode< QskLinesNode >( node ); + linesNode->updateLines( lineColor, lineWidth, lineStipple, + QTransform(), lines ); + + return linesNode; +} + class QskSkinlet::PrivateData { public: @@ -575,6 +610,34 @@ QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable, borderWidth, borderColor, fillGradient, arcMetrics ); } +QSGNode* QskSkinlet::updateLineNode( const QskSkinnable* skinnable, + QSGNode* node, const QLineF& line, QskAspect::Subcontrol subControl ) +{ + auto lineStipple = skinnable->stippleMetricsHint( subControl ); + if ( !lineStipple.isValid() ) + lineStipple = Qt::SolidLine; + + const auto lineWidth = skinnable->metric( subControl | QskAspect::Size ); + const auto lineColor = skinnable->color( subControl ); + + return qskUpdateLineNode( skinnable, node, + lineColor, lineWidth, lineStipple, line ); +} + +QSGNode* QskSkinlet::updateLinesNode( const QskSkinnable* skinnable, + QSGNode* node, const QVector< QLineF >& lines, QskAspect::Subcontrol subControl ) +{ + auto lineStipple = skinnable->stippleMetricsHint( subControl ); + if ( !lineStipple.isValid() ) + lineStipple = Qt::SolidLine; + + const auto lineWidth = skinnable->metric( subControl | QskAspect::Size ); + const auto lineColor = skinnable->color( subControl ); + + return qskUpdateLinesNode( skinnable, node, + lineColor, lineWidth, lineStipple, lines ); +} + QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable, QSGNode* node, QskAspect::Subcontrol subControl ) const { diff --git a/src/controls/QskSkinlet.h b/src/controls/QskSkinlet.h index d6476363..44291712 100644 --- a/src/controls/QskSkinlet.h +++ b/src/controls/QskSkinlet.h @@ -111,6 +111,12 @@ class QSK_EXPORT QskSkinlet const QRectF&, const QskGradient&, qreal startAngle, qreal spanAngle, QskAspect::Subcontrol ); + static QSGNode* updateLineNode( const QskSkinnable*, QSGNode*, + const QLineF&, QskAspect::Subcontrol ); + + static QSGNode* updateLinesNode( const QskSkinnable*, + QSGNode*, const QVector< QLineF >&, QskAspect::Subcontrol ); + static QSGNode* updateTextNode( const QskSkinnable*, QSGNode*, const QRectF&, Qt::Alignment, const QString&, QskAspect::Subcontrol ); diff --git a/src/nodes/QskLinesNode.cpp b/src/nodes/QskLinesNode.cpp index 3774963d..7d2d2f7c 100644 --- a/src/nodes/QskLinesNode.cpp +++ b/src/nodes/QskLinesNode.cpp @@ -6,6 +6,7 @@ #include "QskLinesNode.h" #include "QskVertex.h" #include "QskStippleMetrics.h" +#include "QskStippledLineRenderer.h" #include "QskSGNode.h" #include @@ -13,10 +14,10 @@ #include #include #include +#include QSK_QT_PRIVATE_BEGIN #include -#include QSK_QT_PRIVATE_END namespace @@ -31,85 +32,88 @@ namespace return t.dy() + t.m22() * y; } - /* - 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 + class Renderer : public QskStippledLineRenderer { public: - DashStroker( const QskStippleMetrics& metrics ) - : QDashStroker( nullptr ) + inline Renderer( const QskStippleMetrics& metrics ) + : QskStippledLineRenderer( metrics ) { - setDashOffset( metrics.offset() ); - setDashPattern( metrics.pattern() ); - - m_elements.reserve( 2 ); } - QSGGeometry::Point2D* addDashes( QSGGeometry::Point2D* points, + inline QSGGeometry::Point2D* addDashes( QSGGeometry::Point2D* points, qreal x1, qreal y1, qreal x2, qreal y2 ) { - setMoveToHook( addPoint ); - setLineToHook( addPoint ); - m_points = points; - - begin( this ); - - m_elements.add( { QPainterPath::MoveToElement, x1, y1 } ); - m_elements.add( { QPainterPath::LineToElement, x2, y2 } ); - - processCurrentSubpath(); - - end(); - + renderLine( x1, y1, x2, y2 ); return m_points; } - int pointCount( qreal x1, qreal y1, qreal x2, qreal y2 ) - { - /* - There should be a faster way to calculate the - number of points. TODO ... - */ - setMoveToHook( countPoint ); - setLineToHook( countPoint ); - - 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 addPoint( qfixed x, qfixed y, void* data ) + void renderDash( qreal x1, qreal y1, qreal x2, qreal y2 ) override { - auto stroker = reinterpret_cast< DashStroker* >( data ); - ( stroker->m_points++ )->set( x, y ); + m_points++->set( x1, y1 ); + m_points++->set( x2, y2 ); } - static void countPoint( qfixed, qfixed, void* data ) - { - auto stroker = reinterpret_cast< DashStroker* >( data ); - stroker->m_count++; - } - - int m_count = 0; QSGGeometry::Point2D* m_points; }; } +static QSGGeometry::Point2D* qskAddDashes( const QTransform& transform, + int count, const QLineF* lines, const QskStippleMetrics& metrics, + QSGGeometry::Point2D* points ) +{ + if ( count <= 0 ) + return points; + + const bool doTransform = !transform.isIdentity(); + + Renderer renderer( metrics ); + + for ( int i = 0; i < count; i++ ) + { + auto p1 = lines[i].p1(); + auto p2 = lines[i].p2(); + + if ( doTransform ) + { + p1 = transform.map( p1 ); + p2 = transform.map( p2 ); + } + + points = renderer.addDashes( points, p1.x(), p1.y(), p2.x(), p2.y() ); + } + + return points; +} + +static QSGGeometry::Point2D* qskAddLines( const QTransform& transform, + int count, const QLineF* lines, QSGGeometry::Point2D* points ) +{ + if ( count <= 0 ) + return points; + + const bool doTransform = !transform.isIdentity(); + + auto vlines = reinterpret_cast< QskVertex::Line* >( points ); + + for ( int i = 0; i < count; i++ ) + { + auto p1 = lines[i].p1(); + auto p2 = lines[i].p2(); + + if ( doTransform ) + { + p1 = transform.map( p1 ); + p2 = transform.map( p2 ); + } + + vlines++->setLine( p1.x(), p1.y(), p2.x(), p2.y() ); + } + + return reinterpret_cast< QSGGeometry::Point2D* >( vlines ); +} + class QskLinesNodePrivate final : public QSGGeometryNodePrivate { public: @@ -122,6 +126,9 @@ class QskLinesNodePrivate final : public QSGGeometryNodePrivate inline qreal round( bool isHorizontal, qreal v ) const { + if ( !doRound ) + return v; + const auto r2 = 2.0 * devicePixelRatio; const qreal v0 = isHorizontal ? p0.x() : p0.y(); @@ -131,6 +138,19 @@ class QskLinesNodePrivate final : public QSGGeometryNodePrivate return f / devicePixelRatio - v0; } + inline void setLineAttributes( QskLinesNode* node, + const QColor& color, float lineWidth ) + { + if ( color != material.color() ) + { + material.setColor( color ); + node->markDirty( QSGNode::DirtyMaterial ); + } + + if( lineWidth != geometry.lineWidth() ) + geometry.setLineWidth( lineWidth ); + } + QSGGeometry geometry; QSGFlatColorMaterial material; @@ -139,7 +159,9 @@ class QskLinesNodePrivate final : public QSGGeometryNodePrivate qreal devicePixelRatio = 1.0; QskHashValue hash = 0.0; + bool dirty = true; + bool doRound = false; }; QskLinesNode::QskLinesNode() @@ -176,6 +198,12 @@ void QskLinesNode::setGlobalPosition( { Q_D( QskLinesNode ); + if ( d->doRound == false ) + { + d->doRound = true; + d->dirty = true; + } + if ( pos != d->p0 || devicePixelRatio != d->devicePixelRatio ) { d->p0 = pos; @@ -185,26 +213,96 @@ void QskLinesNode::setGlobalPosition( } } -void QskLinesNode::updateLines( const QColor& color, +void QskLinesNode::resetGlobalPosition() +{ + Q_D( QskLinesNode ); + + if ( d->doRound == true ) + { + d->doRound = false; + d->dirty = true; + } +} + +void QskLinesNode::updateRect( const QColor& color, qreal lineWidth, const QskStippleMetrics& stippleMetrics, const QTransform& transform, const QRectF& rect ) { // using QVarLengthArray instead. TODO ... - updateLines( color, lineWidth, stippleMetrics, transform, + updateGrid( color, lineWidth, stippleMetrics, transform, rect, { rect.left(), rect.right() }, { rect.top(), rect.bottom() } ); } +void QskLinesNode::updateLine( const QColor& color, + qreal lineWidth, const QskStippleMetrics& stippleMetrics, + const QTransform& transform, const QPointF& p1, const QPointF& p2 ) +{ + if ( p1 == p2 ) + { + updateLines( color, lineWidth, stippleMetrics, transform, 0, nullptr ); + } + else + { + const QLineF line( p1, p2 ); + updateLines( color, lineWidth, stippleMetrics, transform, 1, &line ); + } +} + void QskLinesNode::updateLines( const QColor& color, + qreal lineWidth, const QskStippleMetrics& stippleMetrics, + const QTransform& transform, const QVector< QLineF >& lines ) +{ + updateLines( color, lineWidth, stippleMetrics, + transform, lines.count(), lines.constData() ); +} + +void QskLinesNode::updateLines( const QColor& color, + qreal lineWidth, const QskStippleMetrics& stippleMetrics, + const QTransform& transform, int count, const QLineF* lines ) +{ + Q_D( QskLinesNode ); + + if ( !stippleMetrics.isValid() || !color.isValid() + || color.alpha() == 0 || count == 0 ) + { + QskSGNode::resetGeometry( this ); + return; + } + + QskHashValue hash = 9784; + + hash = stippleMetrics.hash( hash ); + hash = qHash( transform, hash ); + hash = qHashBits( lines, count * sizeof( QLineF ) ); + + if ( hash != d->hash ) + { + d->dirty = true; + d->hash = hash; + } + + if( d->dirty ) + { + updateGeometry( stippleMetrics, transform, count, lines ); + + markDirty( QSGNode::DirtyGeometry ); + d->dirty = false; + } + + d->setLineAttributes( this, color, lineWidth ); +} + +void QskLinesNode::updateGrid( const QColor& color, qreal lineWidth, const QskStippleMetrics& stippleMetrics, const QTransform& transform, const QRectF& rect, const QVector< qreal >& xValues, const QVector< qreal >& yValues ) { Q_D( QskLinesNode ); - if ( color != d->material.color() ) + if ( !stippleMetrics.isValid() || !color.isValid() || color.alpha() == 0 ) { - d->material.setColor( color ); - markDirty( QSGNode::DirtyMaterial ); + QskSGNode::resetGeometry( this ); + return; } QskHashValue hash = 9784; @@ -223,24 +321,62 @@ void QskLinesNode::updateLines( const QColor& color, if( d->dirty ) { - if ( rect.isEmpty() || !stippleMetrics.isValid() - || !color.isValid() || color.alpha() == 0 ) - { - QskSGNode::resetGeometry( this ); - } - else - { - updateGeometry( stippleMetrics, - transform, rect, xValues, yValues ); - } + updateGeometry( stippleMetrics, transform, rect, xValues, yValues ); markDirty( QSGNode::DirtyGeometry ); d->dirty = false; } - const float lineWidthF = lineWidth; - if( lineWidthF != d->geometry.lineWidth() ) - d->geometry.setLineWidth( lineWidthF ); + d->setLineAttributes( this, color, lineWidth ); +} + +void QskLinesNode::updateGeometry( const QskStippleMetrics& stippleMetrics, + const QTransform& transform, int count, const QLineF* lines ) +{ + Q_D( QskLinesNode ); + + auto& geom = d->geometry; + + QSGGeometry::Point2D* points = nullptr; + + if ( stippleMetrics.isSolid() ) + { + using namespace QskVertex; + + geom.allocate( 2 * count ); + points = geom.vertexDataAsPoint2D(); + + points = qskAddLines( transform, count, lines, points ); + } + else + { + const bool doTransform = !transform.isIdentity(); + + Renderer renderer( stippleMetrics ); + + int lineCount = 0; + for ( int i = 0; i < count; i++ ) + { + auto p1 = lines[i].p1(); + auto p2 = lines[i].p2(); + + if ( doTransform ) + { + p1 = transform.map( p1 ); + p2 = transform.map( p2 ); + } + lineCount += renderer.dashCount( p1, p2 ); + } + + d->geometry.allocate( 2 * lineCount ); + points = d->geometry.vertexDataAsPoint2D(); + + points = qskAddDashes( transform, + count, lines, stippleMetrics, points ); + + } + + Q_ASSERT( geom.vertexCount() == ( points - geom.vertexDataAsPoint2D() ) ); } void QskLinesNode::updateGeometry( @@ -275,12 +411,13 @@ void QskLinesNode::updateGeometry( } else { - DashStroker stroker( stippleMetrics ); + Renderer renderer( stippleMetrics ); - const int countX = stroker.pointCount( 0.0, y1, 0.0, y2 ); - const int countY = stroker.pointCount( x1, 0.0, x2, 0.0 ); + const auto countX = renderer.dashCount( 0.0, y1, 0.0, y2 ); + const auto countY = renderer.dashCount( x1, 0.0, x2, 0.0 ); + const auto count = xValues.count() * countX + yValues.count() * countY; - d->geometry.allocate( xValues.count() * countX + yValues.count() * countY ); + d->geometry.allocate( 2 * count ); points = d->geometry.vertexDataAsPoint2D(); points = setStippledLines( Qt::Vertical, y1, y2, @@ -305,7 +442,7 @@ QSGGeometry::Point2D* QskLinesNode::setStippledLines( if ( count <= 0 ) return points; - DashStroker stroker( stippleMetrics ); + Renderer renderer( stippleMetrics ); // Calculating the dashes for the first line @@ -317,7 +454,7 @@ QSGGeometry::Point2D* QskLinesNode::setStippledLines( auto x = mapX( transform, values[0] ); x = d->round( true, x ); - points = stroker.addDashes( points, x, v1, x, v2 ); + points = renderer.addDashes( points, x, v1, x, v2 ); dashCount = points - line0; } else @@ -325,7 +462,7 @@ QSGGeometry::Point2D* QskLinesNode::setStippledLines( auto y = mapY( transform, values[0] ); y = d->round( false, y ); - points = stroker.addDashes( points, v1, y, v2, y ); + points = renderer.addDashes( points, v1, y, v2, y ); dashCount = points - line0; } diff --git a/src/nodes/QskLinesNode.h b/src/nodes/QskLinesNode.h index 65d1f544..0de6f9ca 100644 --- a/src/nodes/QskLinesNode.h +++ b/src/nodes/QskLinesNode.h @@ -15,6 +15,7 @@ class QskIntervalF; class QskStippleMetrics; class QTransform; class QPointF; +class QLineF; class QQuickItem; class QskLinesNodePrivate; @@ -31,15 +32,29 @@ class QSK_EXPORT QskLinesNode : public QSGGeometryNode void setGlobalPosition( const QPointF&, qreal devicePixelRatio ); void setGlobalPosition( const QQuickItem* ); + void resetGlobalPosition(); - void updateLines( const QColor&, qreal lineWidth, + void updateGrid( const QColor&, qreal lineWidth, const QskStippleMetrics&, const QTransform&, const QRectF&, const QVector< qreal >&, const QVector< qreal >& ); - void updateLines( const QColor&, qreal lineWidth, + void updateRect( const QColor&, qreal lineWidth, const QskStippleMetrics&, const QTransform&, const QRectF& ); + void updateLine( const QColor&, qreal lineWidth, + const QskStippleMetrics&, const QTransform&, + const QPointF&, const QPointF& ); + + void updateLines( const QColor&, qreal lineWidth, + const QskStippleMetrics&, const QTransform&, const QVector< QLineF >& ); + private: + void updateLines( const QColor&, qreal lineWidth, const QskStippleMetrics&, + const QTransform&, int count, const QLineF* ); + + void updateGeometry( const QskStippleMetrics&, const QTransform&, + int count, const QLineF* ); + void updateGeometry( const QskStippleMetrics&, const QTransform&, const QRectF&, const QVector< qreal >&, const QVector< qreal >& ); From 5cda13568df3b3b9aa0f58db45ec55ece07f6de7 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sun, 28 May 2023 12:43:56 +0200 Subject: [PATCH 08/29] avoid QGradient warnings --- src/common/QskGradientStop.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/QskGradientStop.cpp b/src/common/QskGradientStop.cpp index df995ce1..ab255c67 100644 --- a/src/common/QskGradientStop.cpp +++ b/src/common/QskGradientStop.cpp @@ -413,7 +413,7 @@ QGradientStops qskToQGradientStops( const QskGradientStops& stops ) QGradient removes stops at the same position. So we have to insert an invisible dummy offset */ - qStop.first += 0.00001; + qStop.first = qMin( qStop.first + 0.00001, 1.0 ); } qStops += qStop; From d7eca19685638259bdffba244d2ccbdc9b2ba904 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sun, 28 May 2023 12:44:29 +0200 Subject: [PATCH 09/29] fallback code reorganized --- playground/charts/CircularChartSkinlet.cpp | 47 +++++++++++++--------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/playground/charts/CircularChartSkinlet.cpp b/playground/charts/CircularChartSkinlet.cpp index 86af9634..e2c14195 100644 --- a/playground/charts/CircularChartSkinlet.cpp +++ b/playground/charts/CircularChartSkinlet.cpp @@ -30,6 +30,31 @@ namespace { + QConicalGradient qskQConicalGradient( + const QskGradientStops& stops, qreal startAngle, qreal spanAngle ) + { + QskGradientStops scaledStops; + scaledStops.reserve( stops.size() ); + + const auto ratio = qAbs( spanAngle ) / 360.0; + + if ( spanAngle > 0.0 ) + { + for ( auto it = stops.cbegin(); it != stops.cend(); ++it ) + scaledStops += { ratio * it->position(), it->color() }; + } + else + { + for ( auto it = stops.crbegin(); it != stops.crend(); ++it ) + scaledStops += { 1.0 - ratio * it->position(), it->color() }; + } + + QConicalGradient qGradient( QPointF(), startAngle ); + qGradient.setStops( qskToQGradientStops( scaledStops ) ); + + return qGradient; + } + class PaintedArcNode : public QskPaintedNode { public: @@ -98,26 +123,8 @@ namespace QBrush PaintedArcNode::fillBrush( const QskGradient& gradient, const QRectF& rect, qreal startAngle, qreal spanAngle ) const { - const auto stops = gradient.stops(); - - QskGradientStops scaledStops; - scaledStops.reserve( gradient.stops().size() ); - - const auto ratio = qAbs( spanAngle ) / 360.0; - - if ( spanAngle > 0.0 ) - { - for ( auto it = stops.cbegin(); it != stops.cend(); ++it ) - scaledStops += { ratio* it->position(), it->color() }; - } - else - { - for ( auto it = stops.crbegin(); it != stops.crend(); ++it ) - scaledStops += { 1.0 - ratio * it->position(), it->color() }; - } - - QConicalGradient qGradient( QPointF(), startAngle ); - qGradient.setStops( qskToQGradientStops( scaledStops ) ); + const auto qGradient = qskQConicalGradient( + gradient.stops(), startAngle, spanAngle ); const qreal sz = qMax( rect.width(), rect.height() ); const qreal sx = rect.width() / sz; From 0e2f9fd8399f6fa5ad2e818194d3e463bc31a47b Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 30 May 2023 08:12:37 +0200 Subject: [PATCH 10/29] code improved --- playground/charts/ChartView.cpp | 1 - playground/charts/CircularChartSkinlet.cpp | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/playground/charts/ChartView.cpp b/playground/charts/ChartView.cpp index 364846cf..cbdc66cc 100644 --- a/playground/charts/ChartView.cpp +++ b/playground/charts/ChartView.cpp @@ -184,7 +184,6 @@ namespace QPainter painter( &identifier ); painter.setPen( QPen( QskRgb::toTransparent( Qt::black, 100 ), 1 ) ); - painter.setBrush( gradient.toQGradient() ); QLinearGradient qGradient; qGradient.setStops( qskToQGradientStops( gradient.stops() ) ); diff --git a/playground/charts/CircularChartSkinlet.cpp b/playground/charts/CircularChartSkinlet.cpp index e2c14195..79dc7217 100644 --- a/playground/charts/CircularChartSkinlet.cpp +++ b/playground/charts/CircularChartSkinlet.cpp @@ -339,15 +339,6 @@ QSGNode* CircularChartSkinlet::updateArcSegmentNode( QSGNode* node, qreal borderWidth, const QColor& borderColor, const QskGradient& gradient, const QskArcMetrics& metrics ) const { - auto fillGradient = gradient; - - if ( fillGradient.type() == QskGradient::Stops ) - { - fillGradient.setStretchMode( QskGradient::StretchToSize ); - fillGradient.setConicDirection( 0.5, 0.5, - metrics.startAngle(), metrics.spanAngle() ); - } - #if PAINTED_NODE auto arcNode = static_cast< PaintedArcNode* >( node ); if ( arcNode == nullptr ) @@ -356,10 +347,19 @@ QSGNode* CircularChartSkinlet::updateArcSegmentNode( const auto chart = static_cast< const CircularChart* >( skinnable ); arcNode->setArcData( m_data->closedArcRect, metrics, - borderWidth, borderColor, fillGradient, chart->window() ); + borderWidth, borderColor, gradient, chart->window() ); #else Q_UNUSED( skinnable ) + auto fillGradient = gradient; + + if ( fillGradient.type() == QskGradient::Stops ) + { + fillGradient.setStretchMode( QskGradient::StretchToSize ); + fillGradient.setConicDirection( 0.5, 0.5, + metrics.startAngle(), metrics.spanAngle() ); + } + auto arcNode = static_cast< QskArcNode* >( node ); if ( arcNode == nullptr ) arcNode = new QskArcNode(); From 964395085f2a6491ede1385d1a013303ce9c38fe Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Tue, 9 May 2023 15:14:36 +0200 Subject: [PATCH 11/29] gallery: Make sure a radio button is selected --- examples/gallery/button/ButtonPage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/gallery/button/ButtonPage.cpp b/examples/gallery/button/ButtonPage.cpp index 45ff8bb0..047802af 100644 --- a/examples/gallery/button/ButtonPage.cpp +++ b/examples/gallery/button/ButtonPage.cpp @@ -168,6 +168,7 @@ namespace : ButtonBox( Qt::Horizontal, parent ) { auto radioBox1 = new QskRadioBox( { "One", "Two", "Three" }, this ); + radioBox1->setSelectedIndex( 0 ); radioBox1->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed ); auto radioBox2 = new QskRadioBox( { "One", "Two", "Three" }, this ); From b24c1c57cc89a86f828ab5b42e136f23b28d83e3 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 12 May 2023 14:26:24 +0200 Subject: [PATCH 12/29] windows style: Fix copyright --- skins/windows/CMakeLists.txt | 2 +- skins/windows/QskWindowsGlobal.h | 2 +- skins/windows/QskWindowsSkin.cpp | 2 +- skins/windows/QskWindowsSkin.h | 2 +- skins/windows/QskWindowsSkinFactory.cpp | 2 +- skins/windows/QskWindowsSkinFactory.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/skins/windows/CMakeLists.txt b/skins/windows/CMakeLists.txt index 652b471e..c5b2a5c0 100644 --- a/skins/windows/CMakeLists.txt +++ b/skins/windows/CMakeLists.txt @@ -1,5 +1,5 @@ ############################################################################ -# QSkinny - Copyright (C) 2016 Uwe Rathmann +# QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH # SPDX-License-Identifier: BSD-3-Clause ############################################################################ diff --git a/skins/windows/QskWindowsGlobal.h b/skins/windows/QskWindowsGlobal.h index 62a1080f..573192c3 100644 --- a/skins/windows/QskWindowsGlobal.h +++ b/skins/windows/QskWindowsGlobal.h @@ -1,5 +1,5 @@ /****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann + * QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ diff --git a/skins/windows/QskWindowsSkin.cpp b/skins/windows/QskWindowsSkin.cpp index 02434c1f..8d3421a0 100644 --- a/skins/windows/QskWindowsSkin.cpp +++ b/skins/windows/QskWindowsSkin.cpp @@ -1,5 +1,5 @@ /****************************************************************************** - * QSkinny - Copyright (C) 2022 Edelhirsch Software GmbH + * QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ diff --git a/skins/windows/QskWindowsSkin.h b/skins/windows/QskWindowsSkin.h index e00232d3..b59fdea8 100644 --- a/skins/windows/QskWindowsSkin.h +++ b/skins/windows/QskWindowsSkin.h @@ -1,5 +1,5 @@ /****************************************************************************** - * QSkinny - Copyright (C) 2022 Edelhirsch Software GmbH + * QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ diff --git a/skins/windows/QskWindowsSkinFactory.cpp b/skins/windows/QskWindowsSkinFactory.cpp index 1a2091a1..47054b59 100644 --- a/skins/windows/QskWindowsSkinFactory.cpp +++ b/skins/windows/QskWindowsSkinFactory.cpp @@ -1,5 +1,5 @@ /****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann + * QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ diff --git a/skins/windows/QskWindowsSkinFactory.h b/skins/windows/QskWindowsSkinFactory.h index 19396962..857ac5b5 100644 --- a/skins/windows/QskWindowsSkinFactory.h +++ b/skins/windows/QskWindowsSkinFactory.h @@ -1,5 +1,5 @@ /****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann + * QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ From 99cf060deb7158038fa453dd4ee9f99cbc005805 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 12 May 2023 14:33:39 +0200 Subject: [PATCH 13/29] windows style: Style focus indicator --- skins/windows/QskWindowsSkin.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/skins/windows/QskWindowsSkin.cpp b/skins/windows/QskWindowsSkin.cpp index 8d3421a0..1e54dbaf 100644 --- a/skins/windows/QskWindowsSkin.cpp +++ b/skins/windows/QskWindowsSkin.cpp @@ -225,6 +225,12 @@ void Editor::setupDialogButtonBox() void Editor::setupFocusIndicator() { + using Q = QskFocusIndicator; + + setBoxBorderMetrics( Q::Panel, 2 ); + setPadding( Q::Panel, 3 ); + setBoxShape( Q::Panel, 4 ); + setBoxBorderColors( Q::Panel, theme.palette.strokeColor.focusStroke.outer ); } void Editor::setupInputPanel() From 6d93cc5716c14cb082be44cebb3bab7beb1c04f6 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 12 May 2023 15:35:16 +0200 Subject: [PATCH 14/29] styles: Reuse font roles --- skins/material3/QskMaterial3Skin.h | 8 ++++---- skins/windows/QskWindowsSkin.h | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/skins/material3/QskMaterial3Skin.h b/skins/material3/QskMaterial3Skin.h index c63324dc..f6fda892 100644 --- a/skins/material3/QskMaterial3Skin.h +++ b/skins/material3/QskMaterial3Skin.h @@ -127,10 +127,10 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin enum FontRole { - M3BodyMedium = QskSkin::HugeFont + 1, - M3BodyLarge, - M3HeadlineSmall, - M3LabelLarge, + M3BodyMedium = DefaultFont, + M3BodyLarge = LargeFont, + M3HeadlineSmall = SmallFont, + M3LabelLarge = HugeFont, }; static constexpr QskAspect::Variation Filled = QskAspect::NoVariation; diff --git a/skins/windows/QskWindowsSkin.h b/skins/windows/QskWindowsSkin.h index b59fdea8..103a590a 100644 --- a/skins/windows/QskWindowsSkin.h +++ b/skins/windows/QskWindowsSkin.h @@ -349,14 +349,14 @@ class QSK_WINDOWS_EXPORT QskWindowsSkin : public QskSkin enum FontRole { - Caption = QskSkin::HugeFont + 1, // ### define QskSkin enums - Body, - BodyStrong, - BodyLarge, - Subtitle, - Title, + Caption = TinyFont, + Body = DefaultFont, + BodyStrong = SmallFont, + BodyLarge = MediumFont, + Subtitle = LargeFont, + Title = HugeFont, TitleLarge, - Display + Display, }; static constexpr QskAspect::Variation Standard = QskAspect::NoVariation; From 00b4d9af90737bb6e71dd2b8c25cd57d3a6de8cb Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 12 May 2023 16:27:20 +0200 Subject: [PATCH 15/29] Windows style: Style text input and refactor a bit --- skins/windows/QskWindowsSkin.cpp | 168 +++++++++++++++---------------- skins/windows/QskWindowsSkin.h | 12 ++- 2 files changed, 89 insertions(+), 91 deletions(-) diff --git a/skins/windows/QskWindowsSkin.cpp b/skins/windows/QskWindowsSkin.cpp index 1e54dbaf..f97b5e62 100644 --- a/skins/windows/QskWindowsSkin.cpp +++ b/skins/windows/QskWindowsSkin.cpp @@ -54,10 +54,14 @@ #include #include -static const int qskDuration = 150; - namespace { + inline QRgb flattenedColor( QRgb foregroundColor, QRgb backgroundColor ) + { + const qreal alphaRatio = ( ( foregroundColor & QskRgb::AlphaMask ) >> 24 ) / 255.0; + return QskRgb::interpolated( backgroundColor, foregroundColor, alphaRatio ); + } + class Editor : private QskSkinHintTableEditor { public: @@ -105,6 +109,14 @@ namespace return QskGraphicIO::read( path ); } + void setBoxBorderGradient( QskAspect aspect, QskWindowsTheme::BorderGradient gradient, QRgb baseColor ) + { + const QRgb leftTopRightColor = flattenedColor( gradient[ 0 ], baseColor ); + const QRgb bottomColor = flattenedColor( gradient[ 1 ], baseColor ); + + setBoxBorderColors( aspect, { leftTopRightColor, leftTopRightColor, leftTopRightColor, bottomColor } ); + } + const QskWindowsTheme& theme; }; @@ -121,12 +133,6 @@ namespace return font; } - - inline QRgb flattenedColor( QRgb foregroundColor, QRgb backgroundColor ) - { - const qreal alphaRatio = ( ( foregroundColor & QskRgb::AlphaMask ) >> 24 ) / 255.0; - return QskRgb::interpolated( backgroundColor, foregroundColor, alphaRatio ); - } } void Editor::setup() @@ -291,28 +297,17 @@ void Editor::setupPushButton() // Accent buttons: - const QRgb accentRestBorderColor1 = flattenedColor( theme.palette.elevation.accentControl.border[ 0 ], - theme.palette.fillColor.accent.defaultColor ); - - const QRgb accentRestBorderColor2 = flattenedColor( theme.palette.elevation.accentControl.border[ 1 ], - theme.palette.fillColor.accent.defaultColor ); - - setBoxBorderColors( Q::Panel | W::Accent, { accentRestBorderColor1, accentRestBorderColor1, - accentRestBorderColor1, accentRestBorderColor2 } ); + setBoxBorderGradient( Q::Panel | W::Accent, theme.palette.elevation.accentControl.border, + theme.palette.fillColor.accent.defaultColor ); setGradient( Q::Panel | W::Accent, theme.palette.fillColor.accent.defaultColor ); setColor( Q::Text | W::Accent, theme.palette.fillColor.textOnAccent.primary ); setGraphicRole( Q::Icon | W::Accent, QskWindowsSkin::GraphicRoleFillColorTextOnAccentPrimary ); - const QRgb accentHoveredBorderColor1 = flattenedColor( theme.palette.elevation.accentControl.border[ 0 ], - theme.palette.fillColor.accent.secondary ); + setBoxBorderGradient( Q::Panel | W::Accent | Q::Hovered, theme.palette.elevation.accentControl.border, + theme.palette.fillColor.accent.secondary ); - const QRgb accentHoveredBorderColor2 = flattenedColor( theme.palette.elevation.accentControl.border[ 1 ], - theme.palette.fillColor.accent.secondary ); - - setBoxBorderColors( Q::Panel | W::Accent | Q::Hovered, { accentHoveredBorderColor1, accentHoveredBorderColor1, - accentHoveredBorderColor1, accentHoveredBorderColor2 } ); setGradient( Q::Panel | W::Accent | Q::Hovered, theme.palette.fillColor.accent.secondary ); @@ -335,28 +330,18 @@ void Editor::setupPushButton() // Standard buttons: - const QRgb standardRestBorderColor1 = flattenedColor( theme.palette.elevation.control.border[ 0 ], - theme.palette.fillColor.control.defaultColor ); + setBoxBorderGradient( Q::Panel, theme.palette.elevation.control.border, + theme.palette.fillColor.control.defaultColor ); - const QRgb standardRestBorderColor2 = flattenedColor( theme.palette.elevation.control.border[ 1 ], - theme.palette.fillColor.control.defaultColor ); - - setBoxBorderColors( Q::Panel, { standardRestBorderColor1, standardRestBorderColor1, - standardRestBorderColor1, standardRestBorderColor2 } ); setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor ); setColor( Q::Text, theme.palette.fillColor.text.primary ); setGraphicRole( Q::Icon, QskWindowsSkin::GraphicRoleFillColorTextPrimary ); - const QRgb standardHoveredBorderColor1 = flattenedColor( theme.palette.elevation.control.border[ 0 ], - theme.palette.fillColor.control.secondary ); + setBoxBorderGradient( Q::Panel | Q::Hovered, theme.palette.elevation.control.border, + theme.palette.fillColor.control.secondary ); - const QRgb standardHoveredBorderColor2 = flattenedColor( theme.palette.elevation.control.border[ 1 ], - theme.palette.fillColor.control.secondary ); - - setBoxBorderColors( Q::Panel | Q::Hovered, { standardHoveredBorderColor1, standardHoveredBorderColor1, - standardHoveredBorderColor1, standardHoveredBorderColor2 } ); setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.control.secondary ); @@ -408,14 +393,9 @@ void Editor::setupRadioBox() setBoxBorderMetrics( Q::CheckIndicator | Q::Selected, 1 ); setGradient( Q::CheckIndicator | Q::Selected, theme.palette.fillColor.textOnAccent.primary ); - const QRgb panelRestBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ], - theme.palette.fillColor.accent.defaultColor ); + setBoxBorderGradient( Q::CheckIndicator | Q::Selected, theme.palette.elevation.circle.border, + theme.palette.fillColor.accent.defaultColor ); - const QRgb panelRestBorderColor2 = flattenedColor( theme.palette.elevation.circle.border[ 1 ], - theme.palette.fillColor.accent.defaultColor ); - - setBoxBorderColors( Q::CheckIndicator | Q::Selected, { panelRestBorderColor1, panelRestBorderColor1, - panelRestBorderColor1, panelRestBorderColor2 } ); // Hover @@ -424,14 +404,8 @@ void Editor::setupRadioBox() setGradient( Q::CheckIndicatorPanel | Q::Hovered | Q::Selected, theme.palette.fillColor.accent.secondary ); setPadding( Q::CheckIndicatorPanel | Q::Hovered | Q::Selected, { 4, 4 } ); // indicator "strut size" - const QRgb panelHoveredBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ], - theme.palette.fillColor.accent.secondary ); - - const QRgb panelHoveredBorderColor2 = flattenedColor( theme.palette.elevation.circle.border[ 1 ], - theme.palette.fillColor.accent.secondary ); - - setBoxBorderColors( Q::CheckIndicator | Q::Selected, { panelHoveredBorderColor1, panelHoveredBorderColor1, - panelHoveredBorderColor1, panelHoveredBorderColor2 } ); + setBoxBorderGradient( Q::CheckIndicator | Q::Hovered, theme.palette.elevation.circle.border, + theme.palette.fillColor.accent.secondary ); // Pressed @@ -450,14 +424,8 @@ void Editor::setupRadioBox() setPadding( Q::CheckIndicatorPanel | Q::Pressed | Q::Selected, { 6, 6 } ); // indicator "strut size" setBoxBorderMetrics( Q::CheckIndicator | Q::Pressed, 1 ); - const QRgb panelPressedBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ], - theme.palette.fillColor.accent.tertiary ); // ### calculate those colors at skin construction time - - const QRgb panelPressedBorderColor2 = flattenedColor( theme.palette.elevation.circle.border[ 1 ], - theme.palette.fillColor.accent.tertiary ); - - setBoxBorderColors( Q::CheckIndicator | Q::Pressed | Q::Selected, { panelPressedBorderColor1, panelPressedBorderColor1, - panelPressedBorderColor1, panelPressedBorderColor2 } ); + setBoxBorderGradient( Q::CheckIndicator | Q::Pressed | Q::Selected, theme.palette.elevation.circle.border, + theme.palette.fillColor.accent.tertiary ); // Disabled @@ -548,6 +516,51 @@ void Editor::setupTextLabel() void Editor::setupTextInput() { + using Q = QskTextInput; + + setStrutSize( Q::Panel, { -1, 30 } ); + setBoxBorderMetrics( Q::Panel, 1 ); + setBoxShape( Q::Panel, 3 ); + setPadding( Q::Panel, { 11, 0, 11, 0 } ); + + setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter ); + setFontRole( Q::Text, QskWindowsSkin::Body ); + setColor( Q::Text, theme.palette.fillColor.text.secondary ); + + setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor ); + setBoxBorderGradient( Q::Panel, theme.palette.elevation.textControl.border, + theme.palette.fillColor.control.defaultColor ); + + setColor( Q::PanelSelected, theme.palette.fillColor.accent.selectedTextBackground ); + setColor( Q::TextSelected, theme.palette.fillColor.textOnAccent.selectedText ); + + // Hovered: + + setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.control.secondary ); + setBoxBorderGradient( Q::Panel | Q::Hovered, theme.palette.elevation.textControl.border, + theme.palette.fillColor.control.secondary ); + + + // Pressed & Focused: + + for( const auto& state : { Q::Focused, Q::Editing } ) + { + setBoxBorderMetrics( Q::Panel | state, { 1, 1, 1, 2 } ); + + setGradient( Q::Panel | state, theme.palette.fillColor.control.inputActive ); + + auto gradient = theme.palette.elevation.textControl.border; + gradient.at( 1 ) = theme.palette.fillColor.accent.defaultColor; + + setBoxBorderGradient( Q::Panel | state, gradient, theme.palette.fillColor.control.inputActive ); + } + + // Disabled: + + setGradient( Q::Panel | Q::Disabled, theme.palette.fillColor.control.disabled ); + setBoxBorderColors( Q::Panel | Q::Disabled, theme.palette.strokeColor.controlStroke.defaultColor ); + + setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled ); } void Editor::setupSwitchButton() @@ -579,14 +592,8 @@ void Editor::setupSwitchButton() setGradient( Q::Handle, theme.palette.strokeColor.controlStrongStroke.defaultColor ); setGradient( Q::Handle | Q::Checked, theme.palette.fillColor.textOnAccent.primary ); - const QRgb handleRestBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ], - theme.palette.fillColor.accent.defaultColor ); - - const QRgb handleRestBorderColor2 = flattenedColor( theme.palette.elevation.circle.border[ 1 ], - theme.palette.fillColor.accent.defaultColor ); - - setBoxBorderColors( Q::Handle | Q::Checked, { handleRestBorderColor1, handleRestBorderColor1, - handleRestBorderColor1, handleRestBorderColor2 } ); + setBoxBorderGradient( Q::Handle | Q::Checked, theme.palette.elevation.circle.border, + theme.palette.fillColor.accent.defaultColor ); setGradient( Q::Groove | Q::Hovered, theme.palette.fillColor.controlAlt.tertiary ); @@ -597,14 +604,8 @@ void Editor::setupSwitchButton() setGradient( Q::Handle | Q::Hovered, theme.palette.fillColor.text.secondary ); // Handle | Hovered | Checked is the same as in Rest state - const QRgb handleHoveredBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ], - theme.palette.fillColor.accent.secondary ); - - const QRgb handleHoveredBorderColor2 = flattenedColor( theme.palette.elevation.circle.border[ 1 ], - theme.palette.fillColor.accent.secondary ); - - setBoxBorderColors( Q::Handle | Q::Hovered | Q::Checked, { handleHoveredBorderColor1, handleHoveredBorderColor1, - handleHoveredBorderColor1, handleHoveredBorderColor2 } ); + setBoxBorderGradient( Q::Handle | Q::Hovered | Q::Checked, theme.palette.elevation.circle.border, + theme.palette.fillColor.accent.secondary ); setGradient( Q::Groove | Q::Pressed, theme.palette.fillColor.controlAlt.quaternary ); @@ -617,14 +618,8 @@ void Editor::setupSwitchButton() setGradient( Q::Handle | Q::Pressed, theme.palette.strokeColor.controlStrongStroke.defaultColor ); // Handle | Pressed | Checked is the same as in Rest state - const QRgb handlePressedBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ], - theme.palette.fillColor.accent.tertiary ); - - const QRgb handlePressedBorderColor2 = flattenedColor( theme.palette.elevation.circle.border[ 1 ], - theme.palette.fillColor.accent.tertiary ); - - setBoxBorderColors( Q::Handle | Q::Pressed | Q::Checked, { handlePressedBorderColor1, handlePressedBorderColor1, - handlePressedBorderColor1, handlePressedBorderColor2 } ); + setBoxBorderGradient( Q::Handle | Q::Pressed | Q::Checked, theme.palette.elevation.circle.border, + theme.palette.fillColor.accent.tertiary ); setGradient( Q::Groove | Q::Disabled, theme.palette.fillColor.controlAlt.disabled ); @@ -733,7 +728,7 @@ QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors QskRgb::toTransparentF( 0xff000000, 0.1622 ) }; palette.elevation.textControl.border = { QskRgb::toTransparentF( 0xff000000, 0.0578 ), - QskRgb::toTransparentF( 0xff000000, 0.0578 ) }; + palette.fillColor.text.secondary }; palette.elevation.textControl.borderFocused = { QskRgb::toTransparentF( 0xff000000, 0.0578 ), QskRgb::toTransparentF( 0xff000000, 0.0578 ) }; @@ -874,7 +869,8 @@ QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors QskRgb::toTransparentF( 0xffffffff, 0.0698 ) }; palette.elevation.textControl.border = { QskRgb::toTransparentF( 0xffffffff, 0.08 ), - QskRgb::toTransparentF( 0xffffffff, 0.08 ) }; + palette.fillColor.text.secondary }; + palette.elevation.textControl.borderFocused = { QskRgb::toTransparentF( 0xffffffff, 0.08 ), QskRgb::toTransparentF( 0xffffffff, 0.08 ) }; diff --git a/skins/windows/QskWindowsSkin.h b/skins/windows/QskWindowsSkin.h index 103a590a..72a480f5 100644 --- a/skins/windows/QskWindowsSkin.h +++ b/skins/windows/QskWindowsSkin.h @@ -40,6 +40,8 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme QskWindowsTheme( Theme ); QskWindowsTheme( Theme, std::array< QRgb, NumAccentColors > ); + typedef std::array< QRgb, 2 > BorderGradient; + struct FillColor { struct Text @@ -156,23 +158,23 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme { struct Control { - std::array< QRgb, 2 > border; + BorderGradient border; }; struct Circle { - std::array< QRgb, 2 > border; + BorderGradient border; }; struct TextControl { - std::array< QRgb, 2 > border; - std::array< QRgb, 2 > borderFocused; + BorderGradient border; + BorderGradient borderFocused; }; struct AccentControl { - std::array< QRgb, 2 > border; + BorderGradient border; }; Control control; From b5d7c9c52aeff417b6aa4058b77725c4ab3ce034 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Sat, 13 May 2023 08:49:30 +0200 Subject: [PATCH 16/29] Windows style: Style slider --- skins/windows/QskWindowsSkin.cpp | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/skins/windows/QskWindowsSkin.cpp b/skins/windows/QskWindowsSkin.cpp index f97b5e62..d6169122 100644 --- a/skins/windows/QskWindowsSkin.cpp +++ b/skins/windows/QskWindowsSkin.cpp @@ -458,6 +458,44 @@ void Editor::setupSeparator() void Editor::setupSlider() { + using Q = QskSlider; + using A = QskAspect; + + const qreal extent = 22; + setMetric( Q::Panel | A::Size, extent ); + setBoxShape( Q::Panel, 0 ); + setBoxBorderMetrics( Q::Panel, 0 ); + setGradient( Q::Panel, {} ); + + setPadding( Q::Panel | A::Horizontal, QskMargins( 0.5 * extent, 0 ) ); + setPadding( Q::Panel | A::Vertical, QskMargins( 0, 0.5 * extent ) ); + + setMetric( Q::Groove | A::Size, 4 ); + setGradient( Q::Groove, theme.palette.fillColor.controlStrong.defaultColor ); + setBoxShape( Q::Groove, 100, Qt::RelativeSize ); + + setMetric( Q::Fill | A::Size, 4 ); + setGradient( Q::Fill, theme.palette.fillColor.accent.defaultColor ); + setBoxShape( Q::Fill, 100, Qt::RelativeSize ); + + setStrutSize( Q::Handle, { 22, 22 } ); + setGradient( Q::Handle, theme.palette.fillColor.controlSolid.defaultColor ); + setBoxShape( Q::Handle, 100, Qt::RelativeSize ); + setBoxBorderMetrics( Q::Handle, 1 ); + setBoxBorderGradient( Q::Handle, theme.palette.elevation.circle.border, theme.palette.fillColor.controlSolid.defaultColor ); + + setStrutSize( Q::Ripple, { 12, 12 } ); + setGradient( Q::Ripple, theme.palette.fillColor.accent.defaultColor ); + setBoxShape( Q::Ripple, 100, Qt::RelativeSize ); + + setStrutSize( Q::Ripple | Q::Hovered, { 14, 14 } ); + + setStrutSize( Q::Ripple | Q::Pressed, { 10, 10 } ); + setGradient( Q::Ripple | Q::Pressed, theme.palette.fillColor.accent.tertiary ); + + setGradient( Q::Groove | Q::Disabled, theme.palette.fillColor.controlStrong.disabled ); + setGradient( Q::Fill | Q::Disabled, theme.palette.fillColor.accent.disabled ); + setGradient( Q::Ripple | Q::Disabled, theme.palette.fillColor.controlStrong.disabled ); } void Editor::setupSpinBox() From 9e4e31f34942ff42d6481bcf77e51143633945a4 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Sat, 13 May 2023 10:15:02 +0200 Subject: [PATCH 17/29] Windows style: Style spin box and add some use cases in skinlet --- skins/material3/QskMaterial3Skin.cpp | 2 +- skins/windows/QskWindowsSkin.cpp | 59 ++++++++++++++++++ skins/windows/icons.qrc | 2 + .../windows/icons/qvg/spin-box-arrow-down.qvg | Bin 0 -> 1135 bytes skins/windows/icons/qvg/spin-box-arrow-up.qvg | Bin 0 -> 1135 bytes skins/windows/icons/spin-box-arrow-down.svg | 4 ++ skins/windows/icons/spin-box-arrow-up.svg | 4 ++ src/controls/QskSpinBox.cpp | 2 +- src/controls/QskSpinBox.h | 3 +- src/controls/QskSpinBoxSkinlet.cpp | 58 ++++++++++++++--- src/controls/QskSpinBoxSkinlet.h | 13 ++-- 11 files changed, 130 insertions(+), 17 deletions(-) create mode 100644 skins/windows/icons/qvg/spin-box-arrow-down.qvg create mode 100644 skins/windows/icons/qvg/spin-box-arrow-up.qvg create mode 100644 skins/windows/icons/spin-box-arrow-down.svg create mode 100644 skins/windows/icons/spin-box-arrow-up.svg diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index fdbfdc8e..d0113d65 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -861,7 +861,7 @@ void Editor::setupSpinBox() { using Q = QskSpinBox; - setHint( Q::Panel | QskAspect::Style, Q::Buttons ); + setHint( Q::Panel | QskAspect::Style, Q::ButtonsLeftAndRight ); setSpacing( Q::Panel, 4_dp ); setStrutSize( Q::TextPanel, 80_dp, 40_dp ); diff --git a/skins/windows/QskWindowsSkin.cpp b/skins/windows/QskWindowsSkin.cpp index d6169122..a171fe79 100644 --- a/skins/windows/QskWindowsSkin.cpp +++ b/skins/windows/QskWindowsSkin.cpp @@ -500,6 +500,65 @@ void Editor::setupSlider() void Editor::setupSpinBox() { + using Q = QskSpinBox; + + setHint( Q::Panel | QskAspect::Style, Q::ButtonsRight ); + setStrutSize( Q::Panel, { -1, 32 } ); + setBoxBorderMetrics( Q::Panel, 1 ); + setBoxShape( Q::Panel, 3 ); + setPadding( Q::Panel, { 11, 0, 11, 0 } ); + + setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor ); + setBoxBorderGradient( Q::Panel, theme.palette.elevation.control.border, + theme.palette.fillColor.control.defaultColor ); + + setAlignment( Q::Text, Qt::AlignLeft ); + setFontRole( Q::Text, QskWindowsSkin::Body ); + setColor( Q::Text, theme.palette.fillColor.text.primary ); + + setPadding( Q::TextPanel, { 11, 5, 0, 0 } ); + + setStrutSize( Q::UpPanel, 16, 16 ); + setStrutSize( Q::DownPanel, 16, 16 ); + + setStrutSize( Q::UpPanel, 32, 20 ); + setPadding( Q::UpPanel, { 11, 7, 11, 7 } ); + setStrutSize( Q::DownPanel, 34, 20 ); + setPadding( Q::DownPanel, { 11, 7, 13, 7 } ); + + setSymbol( Q::UpIndicator, symbol( "spin-box-arrow-up" ) ); + setSymbol( Q::DownIndicator, symbol( "spin-box-arrow-down" ) ); + + setGraphicRole( Q::UpIndicator, QskWindowsSkin::GraphicRoleFillColorTextSecondary ); + setGraphicRole( Q::DownIndicator, QskWindowsSkin::GraphicRoleFillColorTextSecondary ); + + // Hovered: + + setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.control.secondary ); + setBoxBorderGradient( Q::Panel | Q::Hovered, theme.palette.elevation.textControl.border, + theme.palette.fillColor.control.secondary ); + + + // Focused (Pressed doesn't exist yet): + + setBoxBorderMetrics( Q::Panel | Q::Focused, { 1, 1, 1, 2 } ); + + setGradient( Q::Panel | Q::Focused, theme.palette.fillColor.control.inputActive ); + + auto gradient = theme.palette.elevation.textControl.border; + gradient.at( 1 ) = theme.palette.fillColor.accent.defaultColor; + + setBoxBorderGradient( Q::Panel | Q::Focused, gradient, theme.palette.fillColor.control.inputActive ); + + // Disabled: + + setGradient( Q::Panel | Q::Disabled, theme.palette.fillColor.control.disabled ); + setBoxBorderColors( Q::Panel | Q::Disabled, theme.palette.strokeColor.controlStroke.defaultColor ); + + setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled ); + + setGraphicRole( Q::UpIndicator | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); + setGraphicRole( Q::DownIndicator | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); } void Editor::setupTabBar() diff --git a/skins/windows/icons.qrc b/skins/windows/icons.qrc index b84bca05..97c702ce 100644 --- a/skins/windows/icons.qrc +++ b/skins/windows/icons.qrc @@ -4,5 +4,7 @@ icons/qvg/combo-box-arrow-closed.qvg icons/qvg/combo-box-arrow-open.qvg icons/qvg/segmented-button-check.qvg + icons/qvg/spin-box-arrow-down.qvg + icons/qvg/spin-box-arrow-up.qvg diff --git a/skins/windows/icons/qvg/spin-box-arrow-down.qvg b/skins/windows/icons/qvg/spin-box-arrow-down.qvg new file mode 100644 index 0000000000000000000000000000000000000000..2825e1fbbd0b7fd4dd919b2c0f377d7e6811a94d GIT binary patch literal 1135 zcmWFx_I77rU|?ouVrB?nu>SyL0|6uB|Njsc16&NoN2g(W(8XbVn7ji_0EuR#g+)N~ z*+F(Fg9!TvAQDJ_g3v&c2`=^_foZi z6UAEl*AN=4_bEi){v|{`Slx>Qj6C^O-1aYkJP2U6e*O{)G;|I-e<_T z-Mt3cJO?EnhTuonRFLg;P;vkph$P13pj7;SjjZM!Br#?Or3L?|tCWPGns@B~LDBoE zDE2D7`Tv^T3nlyn>o&X&Nv=?gLS4j9k#Gv+mgM<%I zjL|`q_kWZ2zS9n35E>}PIJOgS5yl4&cB*B^ViKPyhg}U;+Tz{On!; literal 0 HcmV?d00001 diff --git a/skins/windows/icons/qvg/spin-box-arrow-up.qvg b/skins/windows/icons/qvg/spin-box-arrow-up.qvg new file mode 100644 index 0000000000000000000000000000000000000000..3ae75f325009d6b145bd2ea1483a625bd41e0a35 GIT binary patch literal 1135 zcmWFx_I77rU|?ouVrB?nu>SyL0|6uB|Njsc16&NoN2g(W(8XbVn7ji_0EuR#g+)N~ z*+F(Fg9!TvAd-Q>LAU`-0|_RCm;}S}qiewaw|}Vr-)v1vxr5L?hKt+9BZ2Ce?H~95 z-}6MV)f8`0MUm)`wgzdn3>~F>Y%Z)hk9;DYncm~*P z`x`(W1TZ^@Kp043Ob#OH|0Aq|cOr=a)gAn==ka1Wig}{E|C_Y;okp^k(Lw3h|AV6U zQ<2=qEC|7&(H6n{8?Ljn{A2>&9)8lcW&U_yvJ2fGOWcrbk=4B8APVF`0MI-KFbhcxsF#N!_|Y{LBr#?O z#rq5yx4YM%n5Vdt!S0p9YzKtBjPNl1(*9?s@}fCF!x`;Ang8Qh_gfoD9h3b>cCb9M zdG_z^|9zg&`W4w;`!`_cF(8RC*}piz$dg~ijU>iw|MUZcv-G`Y6!T!|1>rs>c)CIg oKScUNgfl{{0pb7%$q34qf$%&?i|pcnY#)@($UuVv0BAN70Ooe#I{*Lx literal 0 HcmV?d00001 diff --git a/skins/windows/icons/spin-box-arrow-down.svg b/skins/windows/icons/spin-box-arrow-down.svg new file mode 100644 index 00000000..a3ffcd48 --- /dev/null +++ b/skins/windows/icons/spin-box-arrow-down.svg @@ -0,0 +1,4 @@ + + + + diff --git a/skins/windows/icons/spin-box-arrow-up.svg b/skins/windows/icons/spin-box-arrow-up.svg new file mode 100644 index 00000000..34301711 --- /dev/null +++ b/skins/windows/icons/spin-box-arrow-up.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/controls/QskSpinBox.cpp b/src/controls/QskSpinBox.cpp index 693d6b76..9959cac7 100644 --- a/src/controls/QskSpinBox.cpp +++ b/src/controls/QskSpinBox.cpp @@ -173,7 +173,7 @@ void QskSpinBox::resetDecoration() QskSpinBox::Decoration QskSpinBox::decoration() const { - return flagHint< QskSpinBox::Decoration >( aspectDecoration(), Buttons ); + return flagHint< QskSpinBox::Decoration >( aspectDecoration(), ButtonsLeftAndRight ); } void QskSpinBox::setTextAlignment( Qt::Alignment alignment ) diff --git a/src/controls/QskSpinBox.h b/src/controls/QskSpinBox.h index d1066109..5837e951 100644 --- a/src/controls/QskSpinBox.h +++ b/src/controls/QskSpinBox.h @@ -37,7 +37,8 @@ class QSK_EXPORT QskSpinBox : public QskBoundedValueInput { NoDecoration, - Buttons, + ButtonsLeftAndRight, + ButtonsRight, UpDownControl }; Q_ENUM( Decoration ) diff --git a/src/controls/QskSpinBoxSkinlet.cpp b/src/controls/QskSpinBoxSkinlet.cpp index f8a5df08..b0394f30 100644 --- a/src/controls/QskSpinBoxSkinlet.cpp +++ b/src/controls/QskSpinBoxSkinlet.cpp @@ -38,8 +38,8 @@ static inline QskAspect::States qskButtonStates( QskSpinBoxSkinlet::QskSpinBoxSkinlet( QskSkin* ) { - setNodeRoles( { UpPanel, DownPanel, TextPanel, - UpIndicator, DownIndicator, Text } ); + setNodeRoles( { PanelRole, UpPanelRole, DownPanelRole, TextPanelRole, + UpIndicatorRole, DownIndicatorRole, TextRole } ); } QRectF QskSpinBoxSkinlet::subControlRect( const QskSkinnable* skinnable, @@ -50,6 +50,9 @@ QRectF QskSpinBoxSkinlet::subControlRect( const QskSkinnable* skinnable, QskSkinStateChanger stateChanger( skinnable ); stateChanger.setStates( qskButtonStates( skinnable, subControl ) ); + if ( subControl == Q::Panel ) + return contentsRect; + if ( subControl == Q::DownIndicator ) return skinnable->subControlContentsRect( contentsRect, Q::DownPanel ); @@ -77,36 +80,41 @@ QSGNode* QskSpinBoxSkinlet::updateSubNode( switch( nodeRole ) { - case UpPanel: + case PanelRole: + { + return updateBoxNode( skinnable, node, Q::Panel ); + } + + case UpPanelRole: { stateChanger.setStates( qskButtonStates( skinnable, Q::UpPanel ) ); return updateBoxNode( skinnable, node, Q::UpPanel ); } - case DownPanel: + case DownPanelRole: { stateChanger.setStates( qskButtonStates( skinnable, Q::DownPanel ) ); return updateBoxNode( skinnable, node, Q::DownPanel ); } - case UpIndicator: + case UpIndicatorRole: { stateChanger.setStates( qskButtonStates( skinnable, Q::UpIndicator ) ); return updateSymbolNode( skinnable, node, Q::UpIndicator ); } - case DownIndicator: + case DownIndicatorRole: { stateChanger.setStates( qskButtonStates( skinnable, Q::DownIndicator ) ); return updateSymbolNode( skinnable, node, Q::DownIndicator ); } - case TextPanel: + case TextPanelRole: { return updateBoxNode( skinnable, node, Q::TextPanel ); } - case Text: + case TextRole: { auto spinBox = static_cast< const QskSpinBox* >( skinnable ); @@ -141,6 +149,16 @@ QRectF QskSpinBoxSkinlet::textPanelRect( if ( w > 0.0 ) r.setRight( r.right() - spacing - w ); } + else if ( decoration == Q::ButtonsRight ) + { + const auto w1 = subControlRect( skinnable, rect, Q::DownPanel ).width(); + if ( w1 > 0.0 ) + r.setRight( r.right() - w1 - spacing ); + + const auto w2 = subControlRect( skinnable, rect, Q::UpPanel ).width(); + if ( w2 > 0.0 ) + r.setRight( r.right() - w2 - spacing ); + } else { const auto w1 = subControlRect( skinnable, rect, Q::DownPanel ).width(); @@ -180,6 +198,30 @@ QRectF QskSpinBoxSkinlet::buttonRect( const QskSkinnable* skinnable, x = rect.right() - w; y = ( subControl == Q::UpPanel ) ? rect.top() : rect.bottom() - h; } + else if ( decoration == Q::ButtonsRight ) + { + const auto hint = spinBox->strutSizeHint( subControl ); + + h = hint.height(); + if ( h <= 0.0 ) + h = rect.height(); + + w = hint.width(); + if ( w <= 0.0 ) + w = h; + + if( subControl == Q::UpPanel ) + { + const auto downRect = buttonRect( skinnable, rect, Q::DownPanel ); + x = downRect.left() - w; + } + else + { + x = rect.right() - w; + } + + y = 0.5 * ( rect.height() - h ); + } else { const auto hint = spinBox->strutSizeHint( subControl ); diff --git a/src/controls/QskSpinBoxSkinlet.h b/src/controls/QskSpinBoxSkinlet.h index 72eb8840..81fc3fdb 100644 --- a/src/controls/QskSpinBoxSkinlet.h +++ b/src/controls/QskSpinBoxSkinlet.h @@ -18,14 +18,15 @@ class QSK_EXPORT QskSpinBoxSkinlet : public QskSkinlet enum NodeRole { - TextPanel, - Text, + PanelRole, + TextPanelRole, + TextRole, - UpPanel, - UpIndicator, + UpPanelRole, + UpIndicatorRole, - DownPanel, - DownIndicator, + DownPanelRole, + DownIndicatorRole, RoleCount }; From 34776ee66432d261b79c7bf62d74b5c2eab54eb7 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Mon, 5 Jun 2023 10:42:05 +0200 Subject: [PATCH 18/29] using QskLinesNode in the dials example --- playground/dials/DialSkinlet.cpp | 96 ++++---------------------------- src/nodes/QskLinesNode.cpp | 13 +++++ src/nodes/QskLinesNode.h | 5 ++ 3 files changed, 29 insertions(+), 85 deletions(-) diff --git a/playground/dials/DialSkinlet.cpp b/playground/dials/DialSkinlet.cpp index 79f4c2ad..243145fe 100644 --- a/playground/dials/DialSkinlet.cpp +++ b/playground/dials/DialSkinlet.cpp @@ -11,73 +11,14 @@ #include #include #include +#include #include +#include #include #include -#include -#include #include -namespace -{ - class LinesNode : public QSGGeometryNode - { - public: - LinesNode( int lineCount = 0 ) - : m_geometry( QSGGeometry::defaultAttributes_Point2D(), 2 * lineCount ) - { - m_geometry.setDrawingMode( QSGGeometry::DrawLines ); - m_geometry.setVertexDataPattern( QSGGeometry::StaticPattern ); - - setGeometry( &m_geometry ); - setMaterial( &m_material ); - } - - void setColor( const QColor& color ) - { - if ( color != m_material.color() ) - { - m_material.setColor( color ); - markDirty( QSGNode::DirtyMaterial ); - } - } - - private: - QSGFlatColorMaterial m_material; - QSGGeometry m_geometry; - }; - - class TicksNode : public LinesNode - { - public: - TicksNode() - { - } - }; - - class NeedleNode : public LinesNode - { - public: - NeedleNode() - : LinesNode( 1 ) - { - } - - void setData( const QLineF& line, qreal width ) - { - auto vertexData = geometry()->vertexDataAsPoint2D(); - vertexData[ 0 ].set( line.x1(), line.y1() ); - vertexData[ 1 ].set( line.x2(), line.y2() ); - - geometry()->setLineWidth( width ); - geometry()->markVertexDataDirty(); - - markDirty( QSGNode::DirtyGeometry ); - } - }; -} - DialSkinlet::DialSkinlet( QskSkin* skin ) : QskSkinlet( skin ) { @@ -141,22 +82,14 @@ QSGNode* DialSkinlet::updateLabelsNode( if ( labels.count() <= 1 ) return nullptr; - auto ticksNode = static_cast< TicksNode* >( node ); - if ( ticksNode == nullptr ) - ticksNode = new TicksNode(); + auto ticksNode = QskSGNode::ensureNode< QskLinesNode >( node ); const auto color = dial->color( Q::TickLabels ); - ticksNode->setColor( color ); const auto startAngle = dial->minimum(); const auto endAngle = dial->maximum(); const auto step = ( endAngle - startAngle ) / ( labels.count() - 1 ); - auto geometry = ticksNode->geometry(); - geometry->allocate( labels.count() * 2 ); - - auto vertexData = geometry->vertexDataAsPoint2D(); - auto scaleRect = this->scaleRect( dial ); const auto center = scaleRect.center(); @@ -175,6 +108,7 @@ QSGNode* DialSkinlet::updateLabelsNode( // Create a series of tickmarks from minimum to maximum auto labelNode = ticksNode->firstChild(); + QVector< QLineF > ticks; for ( int i = 0; i < labels.count(); ++i, angle += step ) { @@ -187,10 +121,7 @@ QSGNode* DialSkinlet::updateLabelsNode( const auto xEnd = center.x() + needleRadius * cos; const auto yEnd = center.y() + needleRadius * sin; - vertexData[ 0 ].set( xStart, yStart ); - vertexData[ 1 ].set( xEnd, yEnd ); - - vertexData += 2; + ticks += QLineF( xStart, yStart, xEnd, yEnd ); const auto& text = labels.at( i ); @@ -220,10 +151,7 @@ QSGNode* DialSkinlet::updateLabelsNode( } } - geometry->setLineWidth( tickSize.width() ); - geometry->markVertexDataDirty(); - - ticksNode->markDirty( QSGNode::DirtyGeometry ); + ticksNode->updateLines( color, tickSize.width(), ticks ); return ticksNode; } @@ -233,15 +161,13 @@ QSGNode* DialSkinlet::updateNeedleNode( { using Q = Dial; - auto needleNode = static_cast< NeedleNode* >( node ); - if ( needleNode == nullptr ) - needleNode = new NeedleNode(); - - const auto line = needlePoints( dial ); + const auto color = dial->color( Q::Needle ); const auto width = dial->metric( Q::Needle | QskAspect::Size ); - needleNode->setData( line, width * 2 ); - needleNode->setColor( dial->color( Q::Needle ) ); + const auto line = needlePoints( dial ); + + auto needleNode = QskSGNode::ensureNode< QskLinesNode >( node ); + needleNode->updateLine( color, width * 2, line.p1(), line.p2() ); return needleNode; } diff --git a/src/nodes/QskLinesNode.cpp b/src/nodes/QskLinesNode.cpp index 7d2d2f7c..e378776a 100644 --- a/src/nodes/QskLinesNode.cpp +++ b/src/nodes/QskLinesNode.cpp @@ -233,6 +233,12 @@ void QskLinesNode::updateRect( const QColor& color, rect, { rect.left(), rect.right() }, { rect.top(), rect.bottom() } ); } +void QskLinesNode::updateLine( const QColor& color, + qreal lineWidth, const QPointF& p1, const QPointF& p2 ) +{ + updateLine( color, lineWidth, QskStippleMetrics(), QTransform(), p1, p2 ); +} + void QskLinesNode::updateLine( const QColor& color, qreal lineWidth, const QskStippleMetrics& stippleMetrics, const QTransform& transform, const QPointF& p1, const QPointF& p2 ) @@ -248,6 +254,13 @@ void QskLinesNode::updateLine( const QColor& color, } } +void QskLinesNode::updateLines( const QColor& color, + qreal lineWidth, const QVector< QLineF >& lines ) +{ + updateLines( color, lineWidth, QskStippleMetrics(), + QTransform(), lines.count(), lines.constData() ); +} + void QskLinesNode::updateLines( const QColor& color, qreal lineWidth, const QskStippleMetrics& stippleMetrics, const QTransform& transform, const QVector< QLineF >& lines ) diff --git a/src/nodes/QskLinesNode.h b/src/nodes/QskLinesNode.h index 0de6f9ca..711f759d 100644 --- a/src/nodes/QskLinesNode.h +++ b/src/nodes/QskLinesNode.h @@ -41,10 +41,15 @@ class QSK_EXPORT QskLinesNode : public QSGGeometryNode void updateRect( const QColor&, qreal lineWidth, const QskStippleMetrics&, const QTransform&, const QRectF& ); + void updateLine( const QColor&, qreal lineWidth, + const QPointF&, const QPointF& ); + void updateLine( const QColor&, qreal lineWidth, const QskStippleMetrics&, const QTransform&, const QPointF&, const QPointF& ); + void updateLines( const QColor&, qreal lineWidth, const QVector< QLineF >& ); + void updateLines( const QColor&, qreal lineWidth, const QskStippleMetrics&, const QTransform&, const QVector< QLineF >& ); From 0e67ed8aecbe0653928a44031c5aea8317782443 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Tue, 6 Jun 2023 15:24:10 +0200 Subject: [PATCH 19/29] subcontrol layout engine: Allow for laying out more than 2 elements --- src/layouts/QskSubcontrolLayoutEngine.cpp | 67 ++++++++++++++--------- src/layouts/QskSubcontrolLayoutEngine.h | 3 + 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/layouts/QskSubcontrolLayoutEngine.cpp b/src/layouts/QskSubcontrolLayoutEngine.cpp index 6b74fc84..e00b4835 100644 --- a/src/layouts/QskSubcontrolLayoutEngine.cpp +++ b/src/layouts/QskSubcontrolLayoutEngine.cpp @@ -345,31 +345,8 @@ void QskSubcontrolLayoutEngine::setGraphicTextElements( const QskSkinnable* skin having to deal with the details of the layout classes. */ - GraphicElement* graphicElement = nullptr; - if ( !graphicSize.isEmpty() && ( graphicSubControl != QskAspect::NoSubcontrol ) ) - { - graphicElement = dynamic_cast< GraphicElement* >( element( graphicSubControl ) ); - if ( graphicElement == nullptr ) - { - graphicElement = new GraphicElement( skinnable, graphicSubControl ); - m_data->elements.prepend( graphicElement ); - } - - graphicElement->setSourceSize( graphicSize ); - } - - TextElement* textElement = nullptr; - if ( !text.isEmpty() && ( textSubcontrol != QskAspect::NoSubcontrol ) ) - { - textElement = dynamic_cast< TextElement* >( element( textSubcontrol ) ); - if ( textElement == nullptr ) - { - textElement = new TextElement( skinnable, textSubcontrol ); - m_data->elements.append( textElement ); - } - - textElement->setText( text ); - } + auto graphicElement = appendGraphicElement( skinnable, graphicSubControl, graphicSize ); + auto textElement = appendTextElement( skinnable, textSubcontrol, text ); /* Now the difficult part: setting up size policies and the preferred size. @@ -419,6 +396,46 @@ void QskSubcontrolLayoutEngine::setGraphicTextElements( const QskSkinnable* skin } } +QskSubcontrolLayoutEngine::GraphicElement* QskSubcontrolLayoutEngine::appendGraphicElement( const QskSkinnable* skinnable, + QskAspect::Subcontrol graphicSubcontrol, const QSizeF& graphicSize ) +{ + GraphicElement* graphicElement = nullptr; + + if ( !graphicSize.isEmpty() && ( graphicSubcontrol != QskAspect::NoSubcontrol ) ) + { + graphicElement = dynamic_cast< GraphicElement* >( element( graphicSubcontrol ) ); + if ( graphicElement == nullptr ) + { + graphicElement = new GraphicElement( skinnable, graphicSubcontrol ); + m_data->elements.prepend( graphicElement ); + } + + graphicElement->setSourceSize( graphicSize ); + } + + return graphicElement; +} + +QskSubcontrolLayoutEngine::TextElement* QskSubcontrolLayoutEngine::appendTextElement( const QskSkinnable* skinnable, + QskAspect::Subcontrol textSubcontrol, const QString& text ) +{ + TextElement* textElement = nullptr; + + if ( !text.isEmpty() && ( textSubcontrol != QskAspect::NoSubcontrol ) ) + { + textElement = dynamic_cast< TextElement* >( element( textSubcontrol ) ); + if ( textElement == nullptr ) + { + textElement = new TextElement( skinnable, textSubcontrol ); + m_data->elements.append( textElement ); + } + + textElement->setText( text ); + } + + return textElement; +} + void QskSubcontrolLayoutEngine::setFixedContent( QskAspect::Subcontrol subcontrol, Qt::Orientation orientation, Qt::Alignment alignment ) { diff --git a/src/layouts/QskSubcontrolLayoutEngine.h b/src/layouts/QskSubcontrolLayoutEngine.h index 6f929066..c1afc485 100644 --- a/src/layouts/QskSubcontrolLayoutEngine.h +++ b/src/layouts/QskSubcontrolLayoutEngine.h @@ -127,6 +127,9 @@ class QskSubcontrolLayoutEngine : public QskLayoutEngine2D QskAspect::Subcontrol, const QString& text, QskAspect::Subcontrol, const QSizeF& graphicSize ); + GraphicElement* appendGraphicElement( const QskSkinnable*, QskAspect::Subcontrol, const QSizeF& ); + TextElement* appendTextElement( const QskSkinnable*, QskAspect::Subcontrol, const QString& ); + void setFixedContent( QskAspect::Subcontrol, Qt::Orientation, Qt::Alignment ); QRectF subControlRect( QskAspect::Subcontrol ) const; From a394fbacd1b4e64f39be82c1cd482bb7053b1834 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 14 Jun 2023 12:20:46 +0200 Subject: [PATCH 20/29] update of internal cache fixed --- playground/charts/StackedChart.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/playground/charts/StackedChart.cpp b/playground/charts/StackedChart.cpp index 4d7bf219..91aedf7c 100644 --- a/playground/charts/StackedChart.cpp +++ b/playground/charts/StackedChart.cpp @@ -79,6 +79,7 @@ void StackedChart::setSeries( const QVector< ChartSample >& samples ) { // caching the cumulated values + m_data->cumulatedValues.clear(); m_data->cumulatedValues.reserve( samples.size() ); qreal total = 0.0; From 0421066dee15d2ce891217d2895f1e2d44c27092 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 14 Jun 2023 13:00:17 +0200 Subject: [PATCH 21/29] more layout classes being available for application code --- src/layouts/QskGridLayoutEngine.h | 6 +++--- src/layouts/QskLayoutElement.h | 4 ++-- src/layouts/QskLayoutEngine2D.h | 2 +- src/layouts/QskLinearLayoutEngine.h | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/layouts/QskGridLayoutEngine.h b/src/layouts/QskGridLayoutEngine.h index 3ea9a164..37a63ef7 100644 --- a/src/layouts/QskGridLayoutEngine.h +++ b/src/layouts/QskGridLayoutEngine.h @@ -16,7 +16,7 @@ class QQuickItem; class QSizeF; class QRectF; -class QskGridLayoutEngine : public QskLayoutEngine2D +class QSK_EXPORT QskGridLayoutEngine : public QskLayoutEngine2D { public: QskGridLayoutEngine(); @@ -61,8 +61,8 @@ class QskGridLayoutEngine : public QskLayoutEngine2D void invalidateElementCache() override; - void setupChain( Qt::Orientation, - const QskLayoutChain::Segments&, QskLayoutChain& ) const override; + void setupChain( Qt::Orientation, const QskLayoutChain::Segments&, + QskLayoutChain& ) const override final; class PrivateData; std::unique_ptr< PrivateData > m_data; diff --git a/src/layouts/QskLayoutElement.h b/src/layouts/QskLayoutElement.h index 55691bfc..4bebca0b 100644 --- a/src/layouts/QskLayoutElement.h +++ b/src/layouts/QskLayoutElement.h @@ -13,7 +13,7 @@ class QskSizePolicy; class QskLayoutMetrics; -class QskLayoutElement +class QSK_EXPORT QskLayoutElement { public: QskLayoutElement(); @@ -54,7 +54,7 @@ inline qreal QskLayoutElement::widthForHeight( qreal height ) const class QQuickItem; -class QskItemLayoutElement final : public QskLayoutElement +class QSK_EXPORT QskItemLayoutElement final : public QskLayoutElement { public: QskItemLayoutElement( const QQuickItem* ); diff --git a/src/layouts/QskLayoutEngine2D.h b/src/layouts/QskLayoutEngine2D.h index df961136..d468c24c 100644 --- a/src/layouts/QskLayoutEngine2D.h +++ b/src/layouts/QskLayoutEngine2D.h @@ -15,7 +15,7 @@ class QskLayoutElement; -class QskLayoutEngine2D +class QSK_EXPORT QskLayoutEngine2D { public: QskLayoutEngine2D(); diff --git a/src/layouts/QskLinearLayoutEngine.h b/src/layouts/QskLinearLayoutEngine.h index f402c8dc..799cd021 100644 --- a/src/layouts/QskLinearLayoutEngine.h +++ b/src/layouts/QskLinearLayoutEngine.h @@ -16,7 +16,7 @@ class QQuickItem; class QSizeF; class QRectF; -class QskLinearLayoutEngine : public QskLayoutEngine2D +class QSK_EXPORT QskLinearLayoutEngine : public QskLayoutEngine2D { public: QskLinearLayoutEngine( Qt::Orientation, uint dimension ); @@ -58,8 +58,8 @@ class QskLinearLayoutEngine : public QskLayoutEngine2D void invalidateElementCache() override; - virtual void setupChain( Qt::Orientation, - const QskLayoutChain::Segments&, QskLayoutChain& ) const override; + virtual void setupChain( Qt::Orientation, const QskLayoutChain::Segments&, + QskLayoutChain& ) const override final; class PrivateData; std::unique_ptr< PrivateData > m_data; From d56c99b3e76ecc14d489379b44add21bba5f65c8 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 2 Jun 2023 15:14:13 +0200 Subject: [PATCH 22/29] windows style: Style progress bar ... and allow for the case where the bar is bigger than the groove. --- skins/windows/QskWindowsSkin.cpp | 10 ++++++++ src/controls/QskProgressBar.cpp | 4 +++- src/controls/QskProgressBarSkinlet.cpp | 32 ++++++++++++++++++-------- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/skins/windows/QskWindowsSkin.cpp b/skins/windows/QskWindowsSkin.cpp index a171fe79..73ead1f2 100644 --- a/skins/windows/QskWindowsSkin.cpp +++ b/skins/windows/QskWindowsSkin.cpp @@ -276,6 +276,16 @@ void Editor::setupPopup() void Editor::setupProgressBar() { + using Q = QskProgressBar; + using A = QskAspect; + + setMetric( Q::Groove | A::Size, 1 ); + setBoxShape( Q::Groove, 100, Qt::RelativeSize ); + setGradient( Q::Groove, theme.palette.strokeColor.controlStrongStroke.defaultColor ); + + setMetric( Q::Bar| A::Size, 3 ); + setBoxShape( Q::Bar, 100, Qt::RelativeSize ); + setGradient( Q::Bar, theme.palette.fillColor.accent.defaultColor ); } void Editor::setupPushButton() diff --git a/src/controls/QskProgressBar.cpp b/src/controls/QskProgressBar.cpp index d24dbc5b..7a496b2d 100644 --- a/src/controls/QskProgressBar.cpp +++ b/src/controls/QskProgressBar.cpp @@ -192,7 +192,9 @@ void QskProgressBar::resetExtent() qreal QskProgressBar::extent() const { - return metric( Groove | QskAspect::Size ); + auto grooveSize = metric( Groove | QskAspect::Size ); + auto barSize = metric( Bar | QskAspect::Size ); + return qMax( grooveSize, barSize ); } void QskProgressBar::setOrigin( qreal origin ) diff --git a/src/controls/QskProgressBarSkinlet.cpp b/src/controls/QskProgressBarSkinlet.cpp index 391a382f..91de022a 100644 --- a/src/controls/QskProgressBarSkinlet.cpp +++ b/src/controls/QskProgressBarSkinlet.cpp @@ -62,28 +62,29 @@ QRectF QskProgressBarSkinlet::subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const { - const auto bar = static_cast< const QskProgressBar* >( skinnable ); + using Q = QskProgressBar; + const auto bar = static_cast< const Q* >( skinnable ); - if( subControl == QskProgressBar::Groove ) + if( subControl == Q::Groove ) { - const auto extent = bar->extent(); + const auto grooveSize = bar->metric( Q::Groove | QskAspect::Size ); auto rect = contentsRect; if ( bar->orientation() == Qt::Horizontal ) { - rect.setY( rect.y() + 0.5 * ( rect.height() - extent ) ); - rect.setHeight( extent ); + rect.setY( rect.y() + 0.5 * ( rect.height() - grooveSize ) ); + rect.setHeight( grooveSize ); } else { - rect.setX( rect.x() + 0.5 * ( rect.width() - extent ) ); - rect.setWidth( extent ); + rect.setX( rect.x() + 0.5 * ( rect.width() - grooveSize ) ); + rect.setWidth( grooveSize ); } return rect; } - if( subControl == QskProgressBar::Bar ) + if( subControl == Q::Bar ) { return barRect( bar ); } @@ -154,10 +155,23 @@ QSGNode* QskProgressBarSkinlet::updateBarNode( QRectF QskProgressBarSkinlet::barRect( const QskProgressBar* bar ) const { - const auto subControl = QskProgressBar::Groove; + using Q = QskProgressBar; + const auto subControl = Q::Groove; + const auto barSize = bar->metric( Q::Bar | QskAspect::Size ); auto rect = bar->subControlRect( subControl ); + if ( bar->orientation() == Qt::Horizontal ) + { + rect.setY( rect.y() + 0.5 * ( rect.height() - barSize ) ); + rect.setHeight( barSize ); + } + else + { + rect.setX( rect.x() + 0.5 * ( rect.width() - barSize ) ); + rect.setWidth( barSize ); + } + const auto borderMetrics = bar->boxBorderMetricsHint( subControl ); auto m = bar->paddingHint( subControl ); From a35ee482157f788a41f9bed6bd35a0a19bb64177 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 2 Jun 2023 15:51:12 +0200 Subject: [PATCH 23/29] windows style: Style segmented bar --- skins/windows/QskWindowsSkin.cpp | 51 ++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/skins/windows/QskWindowsSkin.cpp b/skins/windows/QskWindowsSkin.cpp index 73ead1f2..15874a8f 100644 --- a/skins/windows/QskWindowsSkin.cpp +++ b/skins/windows/QskWindowsSkin.cpp @@ -460,6 +460,57 @@ void Editor::setupScrollView() void Editor::setupSegmentedBar() { + using Q = QskSegmentedBar; + using A = QskAspect; + + const QSizeF segmentStrutSize( 120, 32 ); + + setBoxBorderMetrics( Q::Panel, 1 ); + + setBoxBorderGradient( Q::Panel, theme.palette.elevation.control.border, + theme.palette.fillColor.control.defaultColor ); + + setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor ); + setSpacing( Q::Panel, 8 ); + + setStrutSize( Q::Icon, { 12, 12 } ); + setGraphicRole( Q::Icon, QskWindowsSkin::GraphicRoleFillColorTextPrimary ); + + setFontRole( Q::Text, QskWindowsSkin::Body ); + setColor( Q::Text, theme.palette.fillColor.text.primary ); + + setStrutSize( Q::Segment | A::Horizontal, segmentStrutSize ); + setStrutSize( Q::Segment | A::Vertical, segmentStrutSize.transposed() ); + setBoxShape( Q::Segment , 4 ); + setPadding( Q::Segment, { 8, 0, 8, 0 } ); + + // Hovered: + setGradient( Q::Segment | Q::Hovered, theme.palette.fillColor.control.secondary ); + + setBoxBorderGradient( Q::Segment | Q::Hovered, theme.palette.elevation.control.border, + theme.palette.fillColor.control.secondary ); + + // Selected: + setGradient( Q::Segment | Q::Selected, theme.palette.fillColor.accent.defaultColor ); + setGraphicRole( Q::Icon | Q::Selected, QskWindowsSkin::GraphicRoleFillColorTextOnAccentPrimary ); + setColor( Q::Text | Q::Selected, theme.palette.fillColor.textOnAccent.primary ); + + // Disabled: + const QRgb standardDisabledBorderColor = flattenedColor( theme.palette.strokeColor.controlStroke.defaultColor, + theme.palette.fillColor.control.disabled ); + + setBoxBorderColors( Q::Segment | Q::Disabled, standardDisabledBorderColor ); + + setGradient( Q::Segment | Q::Disabled, theme.palette.fillColor.control.disabled ); + setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled ); + setGraphicRole( Q::Icon | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); + + + setGradient( Q::Segment | Q::Selected | Q::Disabled, theme.palette.fillColor.accent.disabled ); + setColor( Q::Text | Q::Selected | Q::Disabled, theme.palette.fillColor.textOnAccent.disabled ); + setGraphicRole( Q::Icon | Q::Selected | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextOnAccentDisabled ); + setBoxBorderMetrics( Q::Panel | Q::Selected | Q::Disabled, 0 ); + } void Editor::setupSeparator() From 38e6ac5cd41b412cf7f42bee4398ea0c02029c62 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Mon, 5 Jun 2023 17:05:46 +0200 Subject: [PATCH 24/29] windows style: Style combo box and improve menu --- skins/windows/QskWindowsSkin.cpp | 69 +++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/skins/windows/QskWindowsSkin.cpp b/skins/windows/QskWindowsSkin.cpp index 15874a8f..5f8dfea8 100644 --- a/skins/windows/QskWindowsSkin.cpp +++ b/skins/windows/QskWindowsSkin.cpp @@ -223,6 +223,58 @@ void Editor::setupCheckBox() void Editor::setupComboBox() { + using Q = QskComboBox; + + setStrutSize( Q::Panel, { -1, 32 } ); + setBoxBorderMetrics( Q::Panel, 1 ); + setBoxShape( Q::Panel, 3 ); + setPadding( Q::Panel, { 11, 0, 11, 0 } ); + + setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor ); + setBoxBorderGradient( Q::Panel, theme.palette.elevation.control.border, + theme.palette.fillColor.control.defaultColor ); + + setStrutSize( Q::Icon, 12, 12 ); + setPadding( Q::Icon, { 0, 0, 8, 0 } ); + setGraphicRole( Q::Icon, QskWindowsSkin::GraphicRoleFillColorTextPrimary ); + + setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter ); + setFontRole( Q::Text, QskWindowsSkin::Body ); + setColor( Q::Text, theme.palette.fillColor.text.primary ); + + setStrutSize( Q::StatusIndicator, 12, 12 ); + setSymbol( Q::StatusIndicator, symbol( "spin-box-arrow-down" ) ); + setSymbol( Q::StatusIndicator | Q::PopupOpen, symbol( "spin-box-arrow-up" ) ); + + setGraphicRole( Q::StatusIndicator, QskWindowsSkin::GraphicRoleFillColorTextSecondary ); + + // Hovered: + + setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.control.secondary ); + setBoxBorderGradient( Q::Panel | Q::Hovered, theme.palette.elevation.textControl.border, + theme.palette.fillColor.control.secondary ); + + + // Focused (Pressed doesn't exist yet): + + setBoxBorderMetrics( Q::Panel | Q::Focused, { 1, 1, 1, 2 } ); + + setGradient( Q::Panel | Q::Focused, theme.palette.fillColor.control.inputActive ); + + auto gradient = theme.palette.elevation.textControl.border; + gradient.at( 1 ) = theme.palette.fillColor.accent.defaultColor; + + setBoxBorderGradient( Q::Panel | Q::Focused, gradient, theme.palette.fillColor.control.inputActive ); + + // Disabled: + + setGradient( Q::Panel | Q::Disabled, theme.palette.fillColor.control.disabled ); + setBoxBorderColors( Q::Panel | Q::Disabled, theme.palette.strokeColor.controlStroke.defaultColor ); + + setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled ); + setGraphicRole( Q::Icon | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); + + setGraphicRole( Q::StatusIndicator | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); } void Editor::setupDialogButtonBox() @@ -251,7 +303,7 @@ void Editor::setupMenu() { using Q = QskMenu; - setPadding( Q::Panel, { 16, 6, 16, 6 } ); + setPadding( Q::Panel, { 4, 6, 4, 6 } ); setBoxBorderMetrics( Q::Panel, 1 ); setBoxBorderColors( Q::Panel, theme.palette.strokeColor.surfaceStroke.flyout ); setBoxShape( Q::Panel, 7 ); @@ -262,8 +314,23 @@ void Editor::setupMenu() setPadding( Q::Segment, { 0, 10, 0, 10 } ); setSpacing( Q::Segment, 15 ); + setGradient( Q::Segment | Q::Selected, theme.palette.fillColor.subtle.secondary ); + setBoxBorderMetrics( Q::Segment | Q::Selected, { 3, 0, 0, 0 } ); + + QskGradient selectedGradient( { { 0.0, theme.palette.fillColor.subtle.secondary }, + { 0.25, theme.palette.fillColor.subtle.secondary }, + { 0.25, theme.palette.fillColor.accent.defaultColor }, + { 0.75, theme.palette.fillColor.accent.defaultColor }, + { 0.75, theme.palette.fillColor.subtle.secondary }, + { 1.0, theme.palette.fillColor.subtle.secondary } } ); + setBoxBorderColors( Q::Segment | Q::Selected, selectedGradient ); + setFontRole( Q::Text, QskWindowsSkin::Body ); setColor( Q::Text, theme.palette.fillColor.text.primary ); + + setStrutSize( Q::Icon, 12, 12 ); + setPadding( Q::Icon, { 8, 8, 0, 8 } ); + setGraphicRole( Q::Icon, QskWindowsSkin::GraphicRoleFillColorTextPrimary ); } void Editor::setupPageIndicator() From f616997650ec110a2ed6e0e81449c97861452abf Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 9 Jun 2023 10:34:19 +0200 Subject: [PATCH 25/29] windows style: Style dialog --- examples/gallery/dialog/DialogPage.cpp | 4 +++- skins/windows/QskWindowsSkin.cpp | 29 ++++++++++++++++++++++++-- skins/windows/QskWindowsSkin.h | 4 ++-- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/examples/gallery/dialog/DialogPage.cpp b/examples/gallery/dialog/DialogPage.cpp index 260265ae..bc77a02a 100644 --- a/examples/gallery/dialog/DialogPage.cpp +++ b/examples/gallery/dialog/DialogPage.cpp @@ -37,7 +37,7 @@ namespace , m_type( type ) { setShape( 10 ); - initSizePolicy( QskSizePolicy::Ignored, QskSizePolicy::Ignored ); + initSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Fixed ); const int index = metaObject()->indexOfEnumerator( "ButtonType" ); setText( metaObject()->enumerator( index ).key( m_type ) ); @@ -84,6 +84,8 @@ DialogPage::DialogPage( QQuickItem* parent ) : Page( Qt::Horizontal, parent ) { auto box = new QskLinearBox( Qt::Horizontal, 2, this ); + box->setSpacing( 20 ); + box->setExtraSpacingAt( Qt::BottomEdge ); for ( int i = 0; i < Button::TypeCount; i++ ) new Button( static_cast< Button::ButtonType >( i ), box ); diff --git a/skins/windows/QskWindowsSkin.cpp b/skins/windows/QskWindowsSkin.cpp index 5f8dfea8..8021a2ed 100644 --- a/skins/windows/QskWindowsSkin.cpp +++ b/skins/windows/QskWindowsSkin.cpp @@ -279,6 +279,11 @@ void Editor::setupComboBox() void Editor::setupDialogButtonBox() { + using Q = QskDialogButtonBox; + + setPadding( Q::Panel, 24 ); + setGradient( Q::Panel, theme.palette.background.fillColor.solidBackground.base ); + setPadding(Q::Panel, 20 ); } void Editor::setupFocusIndicator() @@ -339,6 +344,9 @@ void Editor::setupPageIndicator() void Editor::setupPopup() { + using Q = QskPopup; + + setGradient( Q::Overlay, theme.palette.background.fillColor.smoke.defaultColor ); } void Editor::setupProgressBar() @@ -860,6 +868,23 @@ void Editor::setupSwitchButton() void Editor::setupSubWindow() { + using Q = QskSubWindow; + + setPadding( Q::Panel, { 0, 31, 0, 0 } ); + setBoxShape( Q::Panel, 7 ); + setBoxBorderMetrics( Q::Panel, 1 ); + setBoxBorderColors( Q::Panel, theme.palette.strokeColor.surfaceStroke.defaultColor ); + setGradient( Q::Panel, theme.palette.background.fillColor.layer.alt ); + setShadowMetrics( Q::Panel, theme.shadow.dialog.first ); + setShadowColor( Q::Panel, theme.shadow.dialog.second ); + + setHint( Q::TitleBarPanel | QskAspect::Style, Q::TitleBar | Q::Title ); + setPadding( Q::TitleBarPanel, { 24, 31, 24, 0 } ); + + setFontRole( Q::TitleBarText, QskWindowsSkin::Subtitle ); + setColor( Q::TitleBarText, theme.palette.fillColor.text.primary ); + setAlignment( Q::TitleBarText, Qt::AlignLeft ); + setTextOptions( Q::TitleBarText, Qt::ElideRight, QskTextOptions::NoWrap ); } void Editor::setupVirtualKeyboard() @@ -991,7 +1016,7 @@ QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors palette.background.fillColor.cardBackground.secondary = QskRgb::toTransparentF( 0xffF6F6F6, 0.50 ); palette.background.fillColor.cardBackground.tertiary = 0xffffffff; - palette.background.fillColor.stroke.defaultColor = QskRgb::toTransparentF( 0xff000000, 0.30 ); + palette.background.fillColor.smoke.defaultColor = QskRgb::toTransparentF( 0xff000000, 0.30 ); palette.background.fillColor.layer.defaultColor = QskRgb::toTransparentF( 0xffffffff, 0.50 ); palette.background.fillColor.layer.alt = 0xffffffff; @@ -1133,7 +1158,7 @@ QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors palette.background.fillColor.cardBackground.secondary = QskRgb::toTransparentF( 0xffffffff, 0.0326 ); palette.background.fillColor.cardBackground.tertiary = 0xffffffff; // not set in Figma - palette.background.fillColor.stroke.defaultColor = QskRgb::toTransparentF( 0xff000000, 0.30 ); + palette.background.fillColor.smoke.defaultColor = QskRgb::toTransparentF( 0xff000000, 0.30 ); palette.background.fillColor.layer.defaultColor = QskRgb::toTransparentF( 0xff3A3A3A, 0.30 ); palette.background.fillColor.layer.alt = QskRgb::toTransparentF( 0xffffffff, 0.0538 ); diff --git a/skins/windows/QskWindowsSkin.h b/skins/windows/QskWindowsSkin.h index 72a480f5..9d758f2e 100644 --- a/skins/windows/QskWindowsSkin.h +++ b/skins/windows/QskWindowsSkin.h @@ -244,7 +244,7 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme QRgb tertiary; }; - struct Stroke + struct Smoke { QRgb defaultColor; }; @@ -291,7 +291,7 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme }; CardBackground cardBackground; - Stroke stroke; + Smoke smoke; Layer layer; LayerOnAcrylic layerOnAcrylic; LayerOnAccentAcrylic layerOnAccentAcrylic; From 1ccc37d0fcf528bf4fe913ddb08b47456b6a3d19 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 16 Jun 2023 10:59:32 +0200 Subject: [PATCH 26/29] windows skin: Style keyboard --- skins/windows/QskWindowsSkin.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/skins/windows/QskWindowsSkin.cpp b/skins/windows/QskWindowsSkin.cpp index 8021a2ed..6a6c04c4 100644 --- a/skins/windows/QskWindowsSkin.cpp +++ b/skins/windows/QskWindowsSkin.cpp @@ -889,6 +889,20 @@ void Editor::setupSubWindow() void Editor::setupVirtualKeyboard() { + using Q = QskVirtualKeyboard; + + setMargin( Q::ButtonPanel, 2 ); + setGradient( Q::ButtonPanel, theme.palette.fillColor.control.defaultColor ); + setGradient( Q::ButtonPanel | Q::Hovered, theme.palette.fillColor.control.secondary ); + setGradient( Q::ButtonPanel | QskPushButton::Pressed, theme.palette.fillColor.control.tertiary ); + + setColor( Q::ButtonText, theme.palette.fillColor.text.primary ); + setFontRole( Q::ButtonText, QskWindowsSkin::BodyLarge ); + setColor( Q::ButtonText | QskPushButton::Pressed, theme.palette.fillColor.text.secondary ); + + setGradient( Q::Panel, theme.palette.background.fillColor.solidBackground.secondary ); + setPadding( Q::Panel, 8 ); + } QskWindowsTheme::QskWindowsTheme( Theme lightness ) From 58de099acaeaea3fa76ab401d4f91e89967c388a Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Sat, 17 Jun 2023 12:23:34 +0200 Subject: [PATCH 27/29] windows style: Rename to Fluent2 --- examples/iotdashboard/main.cpp | 2 +- skins/CMakeLists.txt | 2 +- skins/{windows => fluent2}/CMakeLists.txt | 8 +- .../QskFluent2Global.h} | 14 +-- .../QskFluent2Skin.cpp} | 104 +++++++++--------- .../QskFluent2Skin.h} | 20 ++-- skins/fluent2/QskFluent2SkinFactory.cpp | 42 +++++++ .../QskFluent2SkinFactory.h} | 14 +-- skins/{windows => fluent2}/icons.qrc | 2 +- .../{windows => fluent2}/icons/checkmark.svg | 0 .../icons/combo-box-arrow-closed.svg | 0 .../icons/combo-box-arrow-open.svg | 0 .../icons/qvg/checkmark.qvg | Bin .../icons/qvg/combo-box-arrow-closed.qvg | Bin .../icons/qvg/combo-box-arrow-open.qvg | Bin .../icons/qvg/segmented-button-check.qvg | Bin .../icons/qvg/spin-box-arrow-down.qvg | Bin .../icons/qvg/spin-box-arrow-up.qvg | Bin .../icons/segmented-button-check.svg | 0 .../icons/spin-box-arrow-down.svg | 0 .../icons/spin-box-arrow-up.svg | 0 skins/fluent2/metadata.json | 4 + skins/windows/QskWindowsSkinFactory.cpp | 42 ------- skins/windows/metadata.json | 4 - support/CMakeLists.txt | 2 +- support/SkinnyNamespace.cpp | 4 +- 26 files changed, 132 insertions(+), 132 deletions(-) rename skins/{windows => fluent2}/CMakeLists.txt (54%) rename skins/{windows/QskWindowsGlobal.h => fluent2/QskFluent2Global.h} (61%) rename skins/{windows/QskWindowsSkin.cpp => fluent2/QskFluent2Skin.cpp} (94%) rename skins/{windows/QskWindowsSkin.h => fluent2/QskFluent2Skin.h} (94%) create mode 100644 skins/fluent2/QskFluent2SkinFactory.cpp rename skins/{windows/QskWindowsSkinFactory.h => fluent2/QskFluent2SkinFactory.h} (65%) rename skins/{windows => fluent2}/icons.qrc (91%) rename skins/{windows => fluent2}/icons/checkmark.svg (100%) rename skins/{windows => fluent2}/icons/combo-box-arrow-closed.svg (100%) rename skins/{windows => fluent2}/icons/combo-box-arrow-open.svg (100%) rename skins/{windows => fluent2}/icons/qvg/checkmark.qvg (100%) rename skins/{windows => fluent2}/icons/qvg/combo-box-arrow-closed.qvg (100%) rename skins/{windows => fluent2}/icons/qvg/combo-box-arrow-open.qvg (100%) rename skins/{windows => fluent2}/icons/qvg/segmented-button-check.qvg (100%) rename skins/{windows => fluent2}/icons/qvg/spin-box-arrow-down.qvg (100%) rename skins/{windows => fluent2}/icons/qvg/spin-box-arrow-up.qvg (100%) rename skins/{windows => fluent2}/icons/segmented-button-check.svg (100%) rename skins/{windows => fluent2}/icons/spin-box-arrow-down.svg (100%) rename skins/{windows => fluent2}/icons/spin-box-arrow-up.svg (100%) create mode 100644 skins/fluent2/metadata.json delete mode 100644 skins/windows/QskWindowsSkinFactory.cpp delete mode 100644 skins/windows/metadata.json diff --git a/examples/iotdashboard/main.cpp b/examples/iotdashboard/main.cpp index a1b7562e..710b7ceb 100644 --- a/examples/iotdashboard/main.cpp +++ b/examples/iotdashboard/main.cpp @@ -71,7 +71,7 @@ int main( int argc, char* argv[] ) qskSkinManager->setPluginPaths( QStringList() ); // no plugins qskSkinManager->unregisterFactory( "material3factory" ); qskSkinManager->unregisterFactory( "squiekfactory" ); - qskSkinManager->unregisterFactory( "windowsfactory" ); + qskSkinManager->unregisterFactory( "fluent2factory" ); qskSkinManager->registerFactory( QStringLiteral( "SampleSkinFactory" ), new SkinFactory() ); diff --git a/skins/CMakeLists.txt b/skins/CMakeLists.txt index 5039716b..fc36f951 100644 --- a/skins/CMakeLists.txt +++ b/skins/CMakeLists.txt @@ -1,3 +1,3 @@ add_subdirectory(squiek) add_subdirectory(material3) -add_subdirectory(windows) +add_subdirectory(fluent2) diff --git a/skins/windows/CMakeLists.txt b/skins/fluent2/CMakeLists.txt similarity index 54% rename from skins/windows/CMakeLists.txt rename to skins/fluent2/CMakeLists.txt index c5b2a5c0..8ae6de16 100644 --- a/skins/windows/CMakeLists.txt +++ b/skins/fluent2/CMakeLists.txt @@ -4,10 +4,10 @@ ############################################################################ set(SOURCES - QskWindowsGlobal.h QskWindowsSkin.h QskWindowsSkin.cpp - QskWindowsSkinFactory.h QskWindowsSkinFactory.cpp + QskFluent2Global.h QskFluent2Skin.h QskFluent2Skin.cpp + QskFluent2SkinFactory.h QskFluent2SkinFactory.cpp ) qt_add_resources(SOURCES icons.qrc) -qsk_add_plugin(windowsskin skins QskWindowsSkinFactory ${SOURCES}) -set_target_properties(windowsskin PROPERTIES DEFINE_SYMBOL QSK_WINDOWS_MAKEDLL ) +qsk_add_plugin(fluent2skin skins QskFluent2SkinFactory ${SOURCES}) +set_target_properties(fluent2skin PROPERTIES DEFINE_SYMBOL QSK_FLUENT2_MAKEDLL ) diff --git a/skins/windows/QskWindowsGlobal.h b/skins/fluent2/QskFluent2Global.h similarity index 61% rename from skins/windows/QskWindowsGlobal.h rename to skins/fluent2/QskFluent2Global.h index 573192c3..5c8a1aec 100644 --- a/skins/windows/QskWindowsGlobal.h +++ b/skins/fluent2/QskFluent2Global.h @@ -3,23 +3,23 @@ * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ -#ifndef QSK_WINDOWS_GLOBAL_H -#define QSK_WINDOWS_GLOBAL_H +#ifndef QSK_FLUENT2_GLOBAL_H +#define QSK_FLUENT2_GLOBAL_H #include "QskGlobal.h" #ifdef QSK_DLL -#if defined( QSK_WINDOWS_MAKEDLL ) // create a DLL library -#define QSK_WINDOWS_EXPORT Q_DECL_EXPORT +#if defined( QSK_FLUENT2_MAKEDLL ) // create a DLL library +#define QSK_FLUENT2_EXPORT Q_DECL_EXPORT #else // use a DLL library -#define QSK_WINDOWS_EXPORT Q_DECL_IMPORT +#define QSK_FLUENT2_EXPORT Q_DECL_IMPORT #endif #endif // QSK_DLL -#ifndef QSK_WINDOWS_EXPORT -#define QSK_WINDOWS_EXPORT +#ifndef QSK_FLUENT2_EXPORT +#define QSK_FLUENT2_EXPORT #endif #endif diff --git a/skins/windows/QskWindowsSkin.cpp b/skins/fluent2/QskFluent2Skin.cpp similarity index 94% rename from skins/windows/QskWindowsSkin.cpp rename to skins/fluent2/QskFluent2Skin.cpp index 6a6c04c4..e72ff49a 100644 --- a/skins/windows/QskWindowsSkin.cpp +++ b/skins/fluent2/QskFluent2Skin.cpp @@ -3,7 +3,7 @@ * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ -#include "QskWindowsSkin.h" +#include "QskFluent2Skin.h" #include @@ -65,7 +65,7 @@ namespace class Editor : private QskSkinHintTableEditor { public: - Editor( QskSkinHintTable* table, const QskWindowsTheme& palette ) + Editor( QskSkinHintTable* table, const QskFluent2Theme& palette ) : QskSkinHintTableEditor( table ) , theme( palette ) { @@ -103,13 +103,13 @@ namespace QskGraphic symbol( const char* name ) const { - const QString path = QStringLiteral( ":windows/icons/qvg/" ) + const QString path = QStringLiteral( ":fluent2/icons/qvg/" ) + name + QStringLiteral( ".qvg" ); return QskGraphicIO::read( path ); } - void setBoxBorderGradient( QskAspect aspect, QskWindowsTheme::BorderGradient gradient, QRgb baseColor ) + void setBoxBorderGradient( QskAspect aspect, QskFluent2Theme::BorderGradient gradient, QRgb baseColor ) { const QRgb leftTopRightColor = flattenedColor( gradient[ 0 ], baseColor ); const QRgb bottomColor = flattenedColor( gradient[ 1 ], baseColor ); @@ -117,7 +117,7 @@ namespace setBoxBorderColors( aspect, { leftTopRightColor, leftTopRightColor, leftTopRightColor, bottomColor } ); } - const QskWindowsTheme& theme; + const QskFluent2Theme& theme; }; QFont createFont( const QString& name, qreal lineHeight, @@ -195,9 +195,9 @@ void Editor::setupCheckBox() const auto checkMark = symbol( "checkmark" ); setSymbol( Q::Indicator | Q::Checked, checkMark, { QskStateCombination::CombinationNoState, Q::Disabled } ); - setGraphicRole( Q::Indicator, QskWindowsSkin::GraphicRoleFillColorTextOnAccentPrimary ); + setGraphicRole( Q::Indicator, QskFluent2Skin::GraphicRoleFillColorTextOnAccentPrimary ); - setFontRole( Q::Text, QskWindowsSkin::Body ); + setFontRole( Q::Text, QskFluent2Skin::Body ); setColor( Q::Text, theme.palette.fillColor.text.primary ); @@ -211,13 +211,13 @@ void Editor::setupCheckBox() setBoxBorderColors( Q::Box | Q::Pressed, theme.palette.strokeColor.controlStrongStroke.disabled ); setGradient( Q::Box | Q::Pressed | Q::Checked, theme.palette.fillColor.accent.tertiary ); setBoxBorderColors( Q::Box | Q::Pressed | Q::Checked, theme.palette.fillColor.accent.tertiary ); - setGraphicRole( Q::Indicator | Q::Pressed | Q::Checked, QskWindowsSkin::GraphicRoleFillColorTextOnAccentSecondary ); + setGraphicRole( Q::Indicator | Q::Pressed | Q::Checked, QskFluent2Skin::GraphicRoleFillColorTextOnAccentSecondary ); setGradient( Q::Box | Q::Disabled, theme.palette.fillColor.controlAlt.disabled ); setBoxBorderColors( Q::Box | Q::Disabled, theme.palette.strokeColor.controlStrongStroke.disabled ); setGradient( Q::Box | Q::Disabled | Q::Checked, theme.palette.fillColor.accent.disabled ); setBoxBorderColors( Q::Box | Q::Disabled | Q::Checked, theme.palette.fillColor.accent.disabled ); - setGraphicRole( Q::Indicator | Q::Disabled | Q::Checked, QskWindowsSkin::GraphicRoleFillColorTextOnAccentDisabled ); + setGraphicRole( Q::Indicator | Q::Disabled | Q::Checked, QskFluent2Skin::GraphicRoleFillColorTextOnAccentDisabled ); setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled ); } @@ -236,17 +236,17 @@ void Editor::setupComboBox() setStrutSize( Q::Icon, 12, 12 ); setPadding( Q::Icon, { 0, 0, 8, 0 } ); - setGraphicRole( Q::Icon, QskWindowsSkin::GraphicRoleFillColorTextPrimary ); + setGraphicRole( Q::Icon, QskFluent2Skin::GraphicRoleFillColorTextPrimary ); setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter ); - setFontRole( Q::Text, QskWindowsSkin::Body ); + setFontRole( Q::Text, QskFluent2Skin::Body ); setColor( Q::Text, theme.palette.fillColor.text.primary ); setStrutSize( Q::StatusIndicator, 12, 12 ); setSymbol( Q::StatusIndicator, symbol( "spin-box-arrow-down" ) ); setSymbol( Q::StatusIndicator | Q::PopupOpen, symbol( "spin-box-arrow-up" ) ); - setGraphicRole( Q::StatusIndicator, QskWindowsSkin::GraphicRoleFillColorTextSecondary ); + setGraphicRole( Q::StatusIndicator, QskFluent2Skin::GraphicRoleFillColorTextSecondary ); // Hovered: @@ -272,9 +272,9 @@ void Editor::setupComboBox() setBoxBorderColors( Q::Panel | Q::Disabled, theme.palette.strokeColor.controlStroke.defaultColor ); setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled ); - setGraphicRole( Q::Icon | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); + setGraphicRole( Q::Icon | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextDisabled ); - setGraphicRole( Q::StatusIndicator | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); + setGraphicRole( Q::StatusIndicator | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextDisabled ); } void Editor::setupDialogButtonBox() @@ -330,12 +330,12 @@ void Editor::setupMenu() { 1.0, theme.palette.fillColor.subtle.secondary } } ); setBoxBorderColors( Q::Segment | Q::Selected, selectedGradient ); - setFontRole( Q::Text, QskWindowsSkin::Body ); + setFontRole( Q::Text, QskFluent2Skin::Body ); setColor( Q::Text, theme.palette.fillColor.text.primary ); setStrutSize( Q::Icon, 12, 12 ); setPadding( Q::Icon, { 8, 8, 0, 8 } ); - setGraphicRole( Q::Icon, QskWindowsSkin::GraphicRoleFillColorTextPrimary ); + setGraphicRole( Q::Icon, QskFluent2Skin::GraphicRoleFillColorTextPrimary ); } void Editor::setupPageIndicator() @@ -366,19 +366,19 @@ void Editor::setupProgressBar() void Editor::setupPushButton() { using Q = QskPushButton; - using W = QskWindowsSkin; + using W = QskFluent2Skin; setStrutSize( Q::Panel, { 120, 32 } ); setBoxShape( Q::Panel, 4 ); setBoxBorderMetrics( Q::Panel, 1 ); - // Windows buttons don't really have icons, + // Fluent buttons don't really have icons, // but for the sake of compatibility with the // gallery app, let's define their style here as well: setStrutSize( Q::Icon, 12, 12 ); setPadding( Q::Icon, { 0, 0, 8, 0 } ); - setFontRole( Q::Text, QskWindowsSkin::Body ); + setFontRole( Q::Text, QskFluent2Skin::Body ); // Accent buttons: @@ -387,7 +387,7 @@ void Editor::setupPushButton() setGradient( Q::Panel | W::Accent, theme.palette.fillColor.accent.defaultColor ); setColor( Q::Text | W::Accent, theme.palette.fillColor.textOnAccent.primary ); - setGraphicRole( Q::Icon | W::Accent, QskWindowsSkin::GraphicRoleFillColorTextOnAccentPrimary ); + setGraphicRole( Q::Icon | W::Accent, QskFluent2Skin::GraphicRoleFillColorTextOnAccentPrimary ); setBoxBorderGradient( Q::Panel | W::Accent | Q::Hovered, theme.palette.elevation.accentControl.border, @@ -399,7 +399,7 @@ void Editor::setupPushButton() setGradient( Q::Panel | W::Accent | Q::Pressed, theme.palette.fillColor.accent.tertiary ); setColor( Q::Text | W::Accent | Q::Pressed, theme.palette.fillColor.textOnAccent.secondary ); - setGraphicRole( Q::Icon | W::Accent | Q::Pressed, QskWindowsSkin::GraphicRoleFillColorTextOnAccentSecondary ); + setGraphicRole( Q::Icon | W::Accent | Q::Pressed, QskFluent2Skin::GraphicRoleFillColorTextOnAccentSecondary ); const QRgb accentPressedBorderColor = flattenedColor( theme.palette.strokeColor.controlStroke.onAccentDefault, theme.palette.fillColor.accent.tertiary ); @@ -409,7 +409,7 @@ void Editor::setupPushButton() setGradient( Q::Panel | W::Accent | Q::Disabled, theme.palette.fillColor.accent.disabled ); setColor( Q::Text | W::Accent | Q::Disabled, theme.palette.fillColor.textOnAccent.disabled ); - setGraphicRole( Q::Icon | W::Accent | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextOnAccentDisabled ); + setGraphicRole( Q::Icon | W::Accent | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextOnAccentDisabled ); setBoxBorderMetrics( Q::Panel | W::Accent | Q::Disabled, 0 ); @@ -421,7 +421,7 @@ void Editor::setupPushButton() setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor ); setColor( Q::Text, theme.palette.fillColor.text.primary ); - setGraphicRole( Q::Icon, QskWindowsSkin::GraphicRoleFillColorTextPrimary ); + setGraphicRole( Q::Icon, QskFluent2Skin::GraphicRoleFillColorTextPrimary ); setBoxBorderGradient( Q::Panel | Q::Hovered, theme.palette.elevation.control.border, @@ -438,7 +438,7 @@ void Editor::setupPushButton() setGradient( Q::Panel | Q::Pressed, theme.palette.fillColor.control.tertiary ); setColor( Q::Text | Q::Pressed, theme.palette.fillColor.text.secondary ); - setGraphicRole( Q::Icon | Q::Pressed, QskWindowsSkin::GraphicRoleFillColorTextSecondary ); + setGraphicRole( Q::Icon | Q::Pressed, QskFluent2Skin::GraphicRoleFillColorTextSecondary ); const QRgb standardDisabledBorderColor = flattenedColor( theme.palette.strokeColor.controlStroke.defaultColor, @@ -448,7 +448,7 @@ void Editor::setupPushButton() setGradient( Q::Panel | Q::Disabled, theme.palette.fillColor.control.disabled ); setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled ); - setGraphicRole( Q::Icon | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); + setGraphicRole( Q::Icon | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextDisabled ); } void Editor::setupRadioBox() @@ -461,7 +461,7 @@ void Editor::setupRadioBox() setStrutSize( Q::CheckIndicatorPanel, { 20, 20 } ); setBoxShape( Q::CheckIndicatorPanel, 100, Qt::RelativeSize ); setBoxBorderMetrics( Q::CheckIndicatorPanel, 1 ); - setFontRole( Q::Text, QskWindowsSkin::Body ); + setFontRole( Q::Text, QskFluent2Skin::Body ); setColor( Q::Text, theme.palette.fillColor.text.primary ); // Rest @@ -549,9 +549,9 @@ void Editor::setupSegmentedBar() setSpacing( Q::Panel, 8 ); setStrutSize( Q::Icon, { 12, 12 } ); - setGraphicRole( Q::Icon, QskWindowsSkin::GraphicRoleFillColorTextPrimary ); + setGraphicRole( Q::Icon, QskFluent2Skin::GraphicRoleFillColorTextPrimary ); - setFontRole( Q::Text, QskWindowsSkin::Body ); + setFontRole( Q::Text, QskFluent2Skin::Body ); setColor( Q::Text, theme.palette.fillColor.text.primary ); setStrutSize( Q::Segment | A::Horizontal, segmentStrutSize ); @@ -567,7 +567,7 @@ void Editor::setupSegmentedBar() // Selected: setGradient( Q::Segment | Q::Selected, theme.palette.fillColor.accent.defaultColor ); - setGraphicRole( Q::Icon | Q::Selected, QskWindowsSkin::GraphicRoleFillColorTextOnAccentPrimary ); + setGraphicRole( Q::Icon | Q::Selected, QskFluent2Skin::GraphicRoleFillColorTextOnAccentPrimary ); setColor( Q::Text | Q::Selected, theme.palette.fillColor.textOnAccent.primary ); // Disabled: @@ -578,12 +578,12 @@ void Editor::setupSegmentedBar() setGradient( Q::Segment | Q::Disabled, theme.palette.fillColor.control.disabled ); setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled ); - setGraphicRole( Q::Icon | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); + setGraphicRole( Q::Icon | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextDisabled ); setGradient( Q::Segment | Q::Selected | Q::Disabled, theme.palette.fillColor.accent.disabled ); setColor( Q::Text | Q::Selected | Q::Disabled, theme.palette.fillColor.textOnAccent.disabled ); - setGraphicRole( Q::Icon | Q::Selected | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextOnAccentDisabled ); + setGraphicRole( Q::Icon | Q::Selected | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextOnAccentDisabled ); setBoxBorderMetrics( Q::Panel | Q::Selected | Q::Disabled, 0 ); } @@ -649,7 +649,7 @@ void Editor::setupSpinBox() theme.palette.fillColor.control.defaultColor ); setAlignment( Q::Text, Qt::AlignLeft ); - setFontRole( Q::Text, QskWindowsSkin::Body ); + setFontRole( Q::Text, QskFluent2Skin::Body ); setColor( Q::Text, theme.palette.fillColor.text.primary ); setPadding( Q::TextPanel, { 11, 5, 0, 0 } ); @@ -665,8 +665,8 @@ void Editor::setupSpinBox() setSymbol( Q::UpIndicator, symbol( "spin-box-arrow-up" ) ); setSymbol( Q::DownIndicator, symbol( "spin-box-arrow-down" ) ); - setGraphicRole( Q::UpIndicator, QskWindowsSkin::GraphicRoleFillColorTextSecondary ); - setGraphicRole( Q::DownIndicator, QskWindowsSkin::GraphicRoleFillColorTextSecondary ); + setGraphicRole( Q::UpIndicator, QskFluent2Skin::GraphicRoleFillColorTextSecondary ); + setGraphicRole( Q::DownIndicator, QskFluent2Skin::GraphicRoleFillColorTextSecondary ); // Hovered: @@ -693,8 +693,8 @@ void Editor::setupSpinBox() setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled ); - setGraphicRole( Q::UpIndicator | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); - setGraphicRole( Q::DownIndicator | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); + setGraphicRole( Q::UpIndicator | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextDisabled ); + setGraphicRole( Q::DownIndicator | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextDisabled ); } void Editor::setupTabBar() @@ -718,10 +718,10 @@ void Editor::setupTabButton() setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter ); - setFontRole( Q::Text, QskWindowsSkin::Body ); + setFontRole( Q::Text, QskFluent2Skin::Body ); setColor( Q::Text, theme.palette.fillColor.text.secondary ); - setFontRole( Q::Text | Q::Checked, QskWindowsSkin::BodyStrong ); + setFontRole( Q::Text | Q::Checked, QskFluent2Skin::BodyStrong ); setColor( Q::Text | Q::Checked, theme.palette.fillColor.text.primary ); setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.subtle.secondary ); @@ -742,7 +742,7 @@ void Editor::setupTextLabel() setPadding( Q::Panel, 10 ); - setFontRole( Q::Text, QskWindowsSkin::Body ); + setFontRole( Q::Text, QskFluent2Skin::Body ); setColor( Q::Text, theme.palette.fillColor.text.primary ); } @@ -757,7 +757,7 @@ void Editor::setupTextInput() setPadding( Q::Panel, { 11, 0, 11, 0 } ); setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter ); - setFontRole( Q::Text, QskWindowsSkin::Body ); + setFontRole( Q::Text, QskFluent2Skin::Body ); setColor( Q::Text, theme.palette.fillColor.text.secondary ); setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor ); @@ -881,7 +881,7 @@ void Editor::setupSubWindow() setHint( Q::TitleBarPanel | QskAspect::Style, Q::TitleBar | Q::Title ); setPadding( Q::TitleBarPanel, { 24, 31, 24, 0 } ); - setFontRole( Q::TitleBarText, QskWindowsSkin::Subtitle ); + setFontRole( Q::TitleBarText, QskFluent2Skin::Subtitle ); setColor( Q::TitleBarText, theme.palette.fillColor.text.primary ); setAlignment( Q::TitleBarText, Qt::AlignLeft ); setTextOptions( Q::TitleBarText, Qt::ElideRight, QskTextOptions::NoWrap ); @@ -897,7 +897,7 @@ void Editor::setupVirtualKeyboard() setGradient( Q::ButtonPanel | QskPushButton::Pressed, theme.palette.fillColor.control.tertiary ); setColor( Q::ButtonText, theme.palette.fillColor.text.primary ); - setFontRole( Q::ButtonText, QskWindowsSkin::BodyLarge ); + setFontRole( Q::ButtonText, QskFluent2Skin::BodyLarge ); setColor( Q::ButtonText | QskPushButton::Pressed, theme.palette.fillColor.text.secondary ); setGradient( Q::Panel, theme.palette.background.fillColor.solidBackground.secondary ); @@ -905,9 +905,9 @@ void Editor::setupVirtualKeyboard() } -QskWindowsTheme::QskWindowsTheme( Theme lightness ) - : QskWindowsTheme( lightness, - { // default Windows accent colors: +QskFluent2Theme::QskFluent2Theme( Theme lightness ) + : QskFluent2Theme( lightness, + { // default Fluent accent colors: 0xff98ecfe, 0xff60ccfe, 0xff0093f9, @@ -919,7 +919,7 @@ QskWindowsTheme::QskWindowsTheme( Theme lightness ) { } -QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors > accentColors ) +QskFluent2Theme::QskFluent2Theme( Theme theme, std::array< QRgb, NumAccentColors > accentColors ) { if( theme == Light ) { @@ -1206,7 +1206,7 @@ QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors } } -QskWindowsSkin::QskWindowsSkin( const QskWindowsTheme& palette, QObject* parent ) +QskFluent2Skin::QskFluent2Skin( const QskFluent2Theme& palette, QObject* parent ) : Inherited( parent ) { setupFonts(); @@ -1216,11 +1216,11 @@ QskWindowsSkin::QskWindowsSkin( const QskWindowsTheme& palette, QObject* parent editor.setup(); } -QskWindowsSkin::~QskWindowsSkin() +QskFluent2Skin::~QskFluent2Skin() { } -void QskWindowsSkin::setupFonts() +void QskFluent2Skin::setupFonts() { static QString fontName( QStringLiteral( "Segoe UI Variable" ) ); Inherited::setupFonts( fontName ); @@ -1235,7 +1235,7 @@ void QskWindowsSkin::setupFonts() setFont( Display, createFont( fontName, 68, 92, 0.0, QFont::DemiBold ) ); } -void QskWindowsSkin::setGraphicColor( GraphicRole role, QRgb rgb ) +void QskFluent2Skin::setGraphicColor( GraphicRole role, QRgb rgb ) { QskColorFilter colorFilter; colorFilter.setMask( QskRgb::RGBAMask ); @@ -1244,7 +1244,7 @@ void QskWindowsSkin::setGraphicColor( GraphicRole role, QRgb rgb ) setGraphicFilter( role, colorFilter ); } -void QskWindowsSkin::setupGraphicFilters( const QskWindowsTheme& theme ) +void QskFluent2Skin::setupGraphicFilters( const QskFluent2Theme& theme ) { setGraphicColor( GraphicRoleFillColorTextDisabled, theme.palette.fillColor.text.disabled ); setGraphicColor( GraphicRoleFillColorTextOnAccentDisabled, theme.palette.fillColor.textOnAccent.disabled ); @@ -1254,4 +1254,4 @@ void QskWindowsSkin::setupGraphicFilters( const QskWindowsTheme& theme ) setGraphicColor( GraphicRoleFillColorTextSecondary, theme.palette.fillColor.text.secondary ); } -#include "moc_QskWindowsSkin.cpp" +#include "moc_QskFluent2Skin.cpp" diff --git a/skins/windows/QskWindowsSkin.h b/skins/fluent2/QskFluent2Skin.h similarity index 94% rename from skins/windows/QskWindowsSkin.h rename to skins/fluent2/QskFluent2Skin.h index 9d758f2e..0f02cc95 100644 --- a/skins/windows/QskWindowsSkin.h +++ b/skins/fluent2/QskFluent2Skin.h @@ -3,10 +3,10 @@ * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ -#ifndef QSK_WINDOWS_SKIN_H -#define QSK_WINDOWS_SKIN_H +#ifndef QSK_FLUENT2_SKIN_H +#define QSK_FLUENT2_SKIN_H -#include "QskWindowsGlobal.h" +#include "QskFluent2Global.h" #include #include @@ -15,7 +15,7 @@ #include -class QSK_WINDOWS_EXPORT QskWindowsTheme +class QSK_FLUENT2_EXPORT QskFluent2Theme { public: enum Theme @@ -37,8 +37,8 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme NumAccentColors }; - QskWindowsTheme( Theme ); - QskWindowsTheme( Theme, std::array< QRgb, NumAccentColors > ); + QskFluent2Theme( Theme ); + QskFluent2Theme( Theme, std::array< QRgb, NumAccentColors > ); typedef std::array< QRgb, 2 > BorderGradient; @@ -329,15 +329,15 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme Shadow shadow; }; -class QSK_WINDOWS_EXPORT QskWindowsSkin : public QskSkin +class QSK_FLUENT2_EXPORT QskFluent2Skin : public QskSkin { Q_OBJECT using Inherited = QskSkin; public: - QskWindowsSkin( const QskWindowsTheme&, QObject* parent = nullptr ); - ~QskWindowsSkin() override; + QskFluent2Skin( const QskFluent2Theme&, QObject* parent = nullptr ); + ~QskFluent2Skin() override; enum GraphicRole { @@ -366,7 +366,7 @@ class QSK_WINDOWS_EXPORT QskWindowsSkin : public QskSkin private: void setupFonts(); - void setupGraphicFilters( const QskWindowsTheme& palette ); + void setupGraphicFilters( const QskFluent2Theme& palette ); void setGraphicColor( GraphicRole, QRgb ); }; diff --git a/skins/fluent2/QskFluent2SkinFactory.cpp b/skins/fluent2/QskFluent2SkinFactory.cpp new file mode 100644 index 00000000..99cfaf55 --- /dev/null +++ b/skins/fluent2/QskFluent2SkinFactory.cpp @@ -0,0 +1,42 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskFluent2SkinFactory.h" +#include "QskFluent2Skin.h" + +static const QString fluent2LightSkinName = QStringLiteral( "Fluent2 Light" ); +static const QString fluent2DarkSkinName = QStringLiteral( "Fluent2 Dark" ); + +QskFluent2SkinFactory::QskFluent2SkinFactory( QObject* parent ) + : QskSkinFactory( parent ) +{ +} + +QskFluent2SkinFactory::~QskFluent2SkinFactory() +{ +} + +QStringList QskFluent2SkinFactory::skinNames() const +{ + return { fluent2LightSkinName, fluent2DarkSkinName }; +} + +QskSkin* QskFluent2SkinFactory::createSkin( const QString& skinName ) +{ + if ( QString::compare( skinName, fluent2LightSkinName, Qt::CaseInsensitive ) == 0 ) + { + QskFluent2Theme theme( QskFluent2Theme::Light ); + return new QskFluent2Skin( theme ); + } + else if ( QString::compare( skinName, fluent2DarkSkinName, Qt::CaseInsensitive ) == 0 ) + { + QskFluent2Theme theme( QskFluent2Theme::Dark ); + return new QskFluent2Skin( theme ); + } + + return nullptr; +} + +#include "moc_QskFluent2SkinFactory.cpp" diff --git a/skins/windows/QskWindowsSkinFactory.h b/skins/fluent2/QskFluent2SkinFactory.h similarity index 65% rename from skins/windows/QskWindowsSkinFactory.h rename to skins/fluent2/QskFluent2SkinFactory.h index 857ac5b5..3903bf73 100644 --- a/skins/windows/QskWindowsSkinFactory.h +++ b/skins/fluent2/QskFluent2SkinFactory.h @@ -3,23 +3,23 @@ * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ -#ifndef QSK_WINDOWS_SKIN_FACTORY_H -#define QSK_WINDOWS_SKIN_FACTORY_H +#ifndef QSK_FLUENT2_SKIN_FACTORY_H +#define QSK_FLUENT2_SKIN_FACTORY_H -#include "QskWindowsGlobal.h" +#include "QskFluent2Global.h" #include -class QSK_WINDOWS_EXPORT QskWindowsSkinFactory : public QskSkinFactory +class QSK_FLUENT2_EXPORT QskFluent2SkinFactory : public QskSkinFactory { Q_OBJECT -#if defined( QSK_WINDOWS_MAKEDLL ) +#if defined( QSK_FLUENT2_MAKEDLL ) Q_PLUGIN_METADATA( IID QskSkinFactoryIID FILE "metadata.json" ) Q_INTERFACES( QskSkinFactory ) #endif public: - QskWindowsSkinFactory( QObject* parent = nullptr ); - ~QskWindowsSkinFactory() override; + QskFluent2SkinFactory( QObject* parent = nullptr ); + ~QskFluent2SkinFactory() override; QStringList skinNames() const override; QskSkin* createSkin( const QString& skinName ) override; diff --git a/skins/windows/icons.qrc b/skins/fluent2/icons.qrc similarity index 91% rename from skins/windows/icons.qrc rename to skins/fluent2/icons.qrc index 97c702ce..4e322fd8 100644 --- a/skins/windows/icons.qrc +++ b/skins/fluent2/icons.qrc @@ -1,5 +1,5 @@ - + icons/qvg/checkmark.qvg icons/qvg/combo-box-arrow-closed.qvg icons/qvg/combo-box-arrow-open.qvg diff --git a/skins/windows/icons/checkmark.svg b/skins/fluent2/icons/checkmark.svg similarity index 100% rename from skins/windows/icons/checkmark.svg rename to skins/fluent2/icons/checkmark.svg diff --git a/skins/windows/icons/combo-box-arrow-closed.svg b/skins/fluent2/icons/combo-box-arrow-closed.svg similarity index 100% rename from skins/windows/icons/combo-box-arrow-closed.svg rename to skins/fluent2/icons/combo-box-arrow-closed.svg diff --git a/skins/windows/icons/combo-box-arrow-open.svg b/skins/fluent2/icons/combo-box-arrow-open.svg similarity index 100% rename from skins/windows/icons/combo-box-arrow-open.svg rename to skins/fluent2/icons/combo-box-arrow-open.svg diff --git a/skins/windows/icons/qvg/checkmark.qvg b/skins/fluent2/icons/qvg/checkmark.qvg similarity index 100% rename from skins/windows/icons/qvg/checkmark.qvg rename to skins/fluent2/icons/qvg/checkmark.qvg diff --git a/skins/windows/icons/qvg/combo-box-arrow-closed.qvg b/skins/fluent2/icons/qvg/combo-box-arrow-closed.qvg similarity index 100% rename from skins/windows/icons/qvg/combo-box-arrow-closed.qvg rename to skins/fluent2/icons/qvg/combo-box-arrow-closed.qvg diff --git a/skins/windows/icons/qvg/combo-box-arrow-open.qvg b/skins/fluent2/icons/qvg/combo-box-arrow-open.qvg similarity index 100% rename from skins/windows/icons/qvg/combo-box-arrow-open.qvg rename to skins/fluent2/icons/qvg/combo-box-arrow-open.qvg diff --git a/skins/windows/icons/qvg/segmented-button-check.qvg b/skins/fluent2/icons/qvg/segmented-button-check.qvg similarity index 100% rename from skins/windows/icons/qvg/segmented-button-check.qvg rename to skins/fluent2/icons/qvg/segmented-button-check.qvg diff --git a/skins/windows/icons/qvg/spin-box-arrow-down.qvg b/skins/fluent2/icons/qvg/spin-box-arrow-down.qvg similarity index 100% rename from skins/windows/icons/qvg/spin-box-arrow-down.qvg rename to skins/fluent2/icons/qvg/spin-box-arrow-down.qvg diff --git a/skins/windows/icons/qvg/spin-box-arrow-up.qvg b/skins/fluent2/icons/qvg/spin-box-arrow-up.qvg similarity index 100% rename from skins/windows/icons/qvg/spin-box-arrow-up.qvg rename to skins/fluent2/icons/qvg/spin-box-arrow-up.qvg diff --git a/skins/windows/icons/segmented-button-check.svg b/skins/fluent2/icons/segmented-button-check.svg similarity index 100% rename from skins/windows/icons/segmented-button-check.svg rename to skins/fluent2/icons/segmented-button-check.svg diff --git a/skins/windows/icons/spin-box-arrow-down.svg b/skins/fluent2/icons/spin-box-arrow-down.svg similarity index 100% rename from skins/windows/icons/spin-box-arrow-down.svg rename to skins/fluent2/icons/spin-box-arrow-down.svg diff --git a/skins/windows/icons/spin-box-arrow-up.svg b/skins/fluent2/icons/spin-box-arrow-up.svg similarity index 100% rename from skins/windows/icons/spin-box-arrow-up.svg rename to skins/fluent2/icons/spin-box-arrow-up.svg diff --git a/skins/fluent2/metadata.json b/skins/fluent2/metadata.json new file mode 100644 index 00000000..9111091b --- /dev/null +++ b/skins/fluent2/metadata.json @@ -0,0 +1,4 @@ +{ + "FactoryId": "Fluent2Factory", + "Skins": [ "Fluent2 Light", "Fluent2 Dark" ] +} diff --git a/skins/windows/QskWindowsSkinFactory.cpp b/skins/windows/QskWindowsSkinFactory.cpp deleted file mode 100644 index 47054b59..00000000 --- a/skins/windows/QskWindowsSkinFactory.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH - * SPDX-License-Identifier: BSD-3-Clause - *****************************************************************************/ - -#include "QskWindowsSkinFactory.h" -#include "QskWindowsSkin.h" - -static const QString windowsLightSkinName = QStringLiteral( "Windows Light" ); -static const QString windowsDarkSkinName = QStringLiteral( "Windows Dark" ); - -QskWindowsSkinFactory::QskWindowsSkinFactory( QObject* parent ) - : QskSkinFactory( parent ) -{ -} - -QskWindowsSkinFactory::~QskWindowsSkinFactory() -{ -} - -QStringList QskWindowsSkinFactory::skinNames() const -{ - return { windowsLightSkinName, windowsDarkSkinName }; -} - -QskSkin* QskWindowsSkinFactory::createSkin( const QString& skinName ) -{ - if ( QString::compare( skinName, windowsLightSkinName, Qt::CaseInsensitive ) == 0 ) - { - QskWindowsTheme theme( QskWindowsTheme::Light ); - return new QskWindowsSkin( theme ); - } - else if ( QString::compare( skinName, windowsDarkSkinName, Qt::CaseInsensitive ) == 0 ) - { - QskWindowsTheme theme( QskWindowsTheme::Dark ); - return new QskWindowsSkin( theme ); - } - - return nullptr; -} - -#include "moc_QskWindowsSkinFactory.cpp" diff --git a/skins/windows/metadata.json b/skins/windows/metadata.json deleted file mode 100644 index 3ff46a6b..00000000 --- a/skins/windows/metadata.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "FactoryId": "WindowsFactory", - "Skins": [ "Windows Light", "Windows Dark" ] -} diff --git a/support/CMakeLists.txt b/support/CMakeLists.txt index f89ac309..4d15724f 100644 --- a/support/CMakeLists.txt +++ b/support/CMakeLists.txt @@ -33,7 +33,7 @@ target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_LIST_DIR}) if(ENABLE_ENSURE_SKINS) target_include_directories(${target} PRIVATE ${CMAKE_SOURCE_DIR}/skins) target_compile_definitions(${target} PRIVATE ENSURE_SKINS) - target_link_libraries(${target} PRIVATE squiekskin material3skin windowsskin) + target_link_libraries(${target} PRIVATE squiekskin material3skin fluent2skin) endif() set(HIDE_SYSTEM_FONTS ON) diff --git a/support/SkinnyNamespace.cpp b/support/SkinnyNamespace.cpp index d86bc42b..c0e5891d 100644 --- a/support/SkinnyNamespace.cpp +++ b/support/SkinnyNamespace.cpp @@ -51,7 +51,7 @@ static bool pluginPath = initPluginPath(); #include #include - #include + #include static void initSkins() { @@ -64,7 +64,7 @@ static bool pluginPath = initPluginPath(); qskSkinManager->registerFactory( "SquiekFactory", new QskSquiekSkinFactory() ); qskSkinManager->registerFactory( "Material3Factory", new QskMaterial3SkinFactory() ); - qskSkinManager->registerFactory( "WindowsFactory", new QskWindowsSkinFactory() ); + qskSkinManager->registerFactory( "Fluent2Factory", new QskFluent2SkinFactory() ); qWarning() << "Couldn't find skin plugins, adding some manually."; } From 1f8283b186b57050d6a28b26893a1d51a7b94402 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 20 Jun 2023 09:20:51 +0200 Subject: [PATCH 28/29] respect the ordering from the skin factories instead of sorting them alphabetically --- src/controls/QskSkinManager.cpp | 15 ++++++--------- support/SkinnyNamespace.cpp | 17 +++++++---------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/controls/QskSkinManager.cpp b/src/controls/QskSkinManager.cpp index d2ad8b04..048a4757 100644 --- a/src/controls/QskSkinManager.cpp +++ b/src/controls/QskSkinManager.cpp @@ -200,7 +200,7 @@ namespace if ( !m_isValid ) const_cast< FactoryMap* >( this )->rebuild(); - return m_skinMap.keys(); + return m_skinNames; } void insertFactory( FactoryLoader* loader ) @@ -269,6 +269,7 @@ namespace void rebuild() { m_skinMap.clear(); + m_skinNames.clear(); // first we try all factories, that have been added manually for ( auto it = m_factoryMap.constBegin(); it != m_factoryMap.constEnd(); ++it ) @@ -287,7 +288,6 @@ namespace rebuild( it.key(), data.loader->skinNames() ); } - m_skinNames = m_skinMap.keys(); m_isValid = true; } @@ -296,7 +296,10 @@ namespace for ( const auto& name : skinNames ) { if ( !m_skinMap.contains( name ) ) + { m_skinMap.insert( name, factoryId ); + m_skinNames += name; + } } } @@ -487,16 +490,10 @@ QskSkin* QskSkinManager::createSkin( const QString& skinName ) const auto factory = map.factory( name ); if ( factory == nullptr ) { - /* - Once the Fusion skin has been implemented it will be used - as fallback. For the moment we implement - another stupid fallback. TODO ... - */ - const auto names = map.skinNames(); if ( !names.isEmpty() ) { - name = names.last(); + name = names.first(); factory = map.factory( name ); } } diff --git a/support/SkinnyNamespace.cpp b/support/SkinnyNamespace.cpp index c0e5891d..31da9c91 100644 --- a/support/SkinnyNamespace.cpp +++ b/support/SkinnyNamespace.cpp @@ -55,7 +55,9 @@ static bool pluginPath = initPluginPath(); static void initSkins() { - if ( qskSkinManager->skinNames().isEmpty() ) + auto skinNames = qskSkinManager->skinNames(); + + if ( skinNames.isEmpty() ) { /* To avoid having problems with not finding the skin plugins @@ -67,17 +69,12 @@ static bool pluginPath = initPluginPath(); qskSkinManager->registerFactory( "Fluent2Factory", new QskFluent2SkinFactory() ); qWarning() << "Couldn't find skin plugins, adding some manually."; + + skinNames = qskSkinManager->skinNames(); } -#if 1 - /* - QskSkinManager is sorting in alphabetic order, but we want to have - the light material skin as initial skin. TODO ... - */ - const auto names = qskSkinManager->skinNames(); - if ( names.count() > 1 ) - qskSetup->setSkin( names[1] ); -#endif + if ( !skinNames.isEmpty() ) + qskSetup->setSkin( skinNames[0] ); } Q_COREAPP_STARTUP_FUNCTION( initSkins ) From 7f368d13dd8d7ab14f245daa60bd7c9831416a3e Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 20 Jun 2023 09:22:33 +0200 Subject: [PATCH 29/29] blocking the Fluent2 skins - we need to fix a couple of issues first --- src/controls/QskSkinManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/controls/QskSkinManager.cpp b/src/controls/QskSkinManager.cpp index 048a4757..5100c05c 100644 --- a/src/controls/QskSkinManager.cpp +++ b/src/controls/QskSkinManager.cpp @@ -83,6 +83,10 @@ namespace const auto factoryData = pluginData.value( TokenData ).toObject(); m_factoryId = factoryData.value( TokenFactoryId ).toString().toLower(); +#if 1 + if ( m_factoryId == "fluent2factory" ) + return false; // we need to solve a couple of problems first +#endif if ( m_factoryId.isEmpty() ) { // Creating a dummy factory id