Merge branch 'master' into features/drawer

This commit is contained in:
Uwe Rathmann 2024-09-17 17:41:52 +02:00
commit 35e6cda013
22 changed files with 329 additions and 458 deletions

View File

@ -54,16 +54,29 @@ macro(qsk_setup_Qt)
# C++, but QSkinny itself does not need the WebEngine at all.
if (QT_VERSION_MAJOR VERSION_LESS 6)
find_package(Qt${QT_VERSION_MAJOR} QUIET OPTIONAL_COMPONENTS WebEngine)
find_package(Qt${QT_VERSION_MAJOR} QUIET
OPTIONAL_COMPONENTS WebEngine)
find_package(Qt${QT_VERSION_MAJOR} QUIET
OPTIONAL_COMPONENTS QuickShapes)
set( Qt5WebEngineQuick_FOUND ${Qt5WebEngine_FOUND} )
set( Qt5QuickShapesPrivate_FOUND ${Qt5QuickShapes_FOUND} )
else()
find_package(Qt${QT_VERSION_MAJOR} QUIET
OPTIONAL_COMPONENTS WebEngineCore WebEngineQuick)
find_package(Qt${QT_VERSION_MAJOR} QUIET
OPTIONAL_COMPONENTS QuickShapesPrivate)
endif()
if( NOT Qt${QT_VERSION_MAJOR}WebEngineQuick_FOUND)
message(STATUS "No Qt/Quick WebEngine support: skipping some unimportant examples")
endif()
if (NOT Qt${QT_VERSION_MAJOR}QuickShapesPrivate_FOUND)
message(STATUS "No Qt/Quick Shapes support: skipping some unimportant examples")
endif()
endif()
endmacro()

View File

@ -150,7 +150,7 @@ void Frame::updateFrameNode( const QRectF& rect, QskBoxRectangleNode* node )
const QskBoxBorderColors borderColors( c1, c1, c2, c2 );
const qreal radius = effectiveRadius( rect, m_radius );
node->updateNode( rect, radius, m_frameWidth, borderColors, m_color );
node->updateBox( rect, radius, m_frameWidth, borderColors, m_color );
}
#include "moc_Frame.cpp"

View File

@ -173,7 +173,7 @@ QSGNode* DiagramSkinlet::updateChartNode( const Diagram* diagram, QSGNode* node
color = diagram->color( barSubcontrol );
const auto shape = diagram->boxShapeHint( barSubcontrol );
barNode->updateNode( barRect, shape, {}, {}, color );
barNode->updateFilling( barRect, shape, color );
}
}
else

View File

@ -5,13 +5,14 @@
set(SOURCES GradientView.h GradientView.cpp main.cpp)
if(TARGET quickshapes_private)
if(TARGET Qt::QuickShapesPrivate)
list(APPEND SOURCES GradientQuickShape.h GradientQuickShape.cpp)
endif()
qsk_add_example(gradients ${SOURCES})
set(target gradients)
qsk_add_example(${target} ${SOURCES})
if(TARGET quickshapes_private)
target_compile_definitions(gradients PRIVATE SHAPE_GRADIENT)
target_link_libraries(gradients PRIVATE quickshapes_private)
if(TARGET Qt::QuickShapesPrivate)
target_compile_definitions(${target} PRIVATE SHAPE_GRADIENT)
target_link_libraries(${target} PRIVATE Qt::QuickShapesPrivate )
endif()

View File

@ -14,7 +14,6 @@ QSK_QT_PRIVATE_BEGIN
#define signals Q_SIGNALS
#endif
#include <private/qquickitem_p.h>
#include <private/qquickshape_p.h>
#include <private/qquickshape_p_p.h>

View File

@ -10,7 +10,6 @@
#endif
#include <QskPaintedNode.h>
#include <QskBoxFillNode.h>
#include <QskBoxRectangleNode.h>
#include <QskGradient.h>
#include <QskGradientDirection.h>
@ -75,20 +74,20 @@ namespace
switch( nodeType )
{
case GradientView::Painted:
text = "QskPaintedNode";
text = "Raster PaintEngine";
break;
case GradientView::BoxRectangle:
text = "QskBoxRectangleNode";
text = "Colored Vertices";
break;
case GradientView::BoxFill:
text = "QskBoxFillNode";
text = "Qskinny Shader";
break;
#ifdef SHAPE_GRADIENT
case GradientView::Shape:
text = "QQuickShapeGenericNode";
text = "Qt/Quick Shape Shader";
break;
#endif
@ -149,6 +148,11 @@ QSGNode* GradientView::updatePaintNode(
{
const QRectF rect( 0, 0, width(), height() );
QskBoxShapeMetrics shape;
#if 0
shape.setRadius( 80 );
#endif
switch( m_nodeType )
{
case Painted:
@ -160,24 +164,17 @@ QSGNode* GradientView::updatePaintNode(
}
case BoxFill:
{
auto node = gradientNode< QskBoxFillNode >( oldNode );
node->updateNode( rect, m_gradient );
auto node = gradientNode< QskBoxRectangleNode >( oldNode );
node->setHint( QskFillNode::PreferColoredGeometry, false );
node->updateFilling( rect, shape, m_gradient );
return node;
}
case BoxRectangle:
{
QskBoxShapeMetrics shape;
shape.setRadius( 80 );
if ( !QskBoxRenderer::isGradientSupported( shape, m_gradient ) )
{
delete oldNode;
return nullptr;
}
auto node = gradientNode< QskBoxRectangleNode >( oldNode );
node->updateNode( rect, shape, m_gradient );
node->setHint( QskFillNode::PreferColoredGeometry, true );
node->updateFilling( rect, shape, m_gradient );
return node;
}

View File

@ -40,9 +40,9 @@ int main( int argc, char* argv[] )
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
// namespace QtWebEngine doesn't exist in Qt6: https://doc.qt.io/qt-5/qtwebengine.html
QtWebEngine::initialize();
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app( argc, argv );
SkinnyShortcut::enable( SkinnyShortcut::Quit | SkinnyShortcut::DebugShortcuts );

View File

@ -107,7 +107,6 @@ list(APPEND HEADERS
nodes/QskBasicLinesNode.h
nodes/QskBoxNode.h
nodes/QskBoxClipNode.h
nodes/QskBoxFillNode.h
nodes/QskBoxRectangleNode.h
nodes/QskBoxRenderer.h
nodes/QskBoxMetrics.h
@ -149,7 +148,6 @@ list(APPEND SOURCES
nodes/QskBasicLinesNode.cpp
nodes/QskBoxNode.cpp
nodes/QskBoxClipNode.cpp
nodes/QskBoxFillNode.cpp
nodes/QskBoxRectangleNode.cpp
nodes/QskBoxRenderer.cpp
nodes/QskBoxMetrics.cpp
@ -164,7 +162,6 @@ list(APPEND SOURCES
nodes/QskLinesNode.cpp
nodes/QskPaintedNode.cpp
nodes/QskPlainTextRenderer.cpp
nodes/QskRectangleNode.cpp
nodes/QskRichTextRenderer.cpp
nodes/QskSceneTexture.cpp
nodes/QskSGNode.cpp

View File

@ -22,7 +22,6 @@
#include "QskGraphicNode.h"
#include "QskGraphic.h"
#include "QskLinesNode.h"
#include "QskRectangleNode.h"
#include "QskSGNode.h"
#include "QskStippleMetrics.h"
#include "QskTextColors.h"
@ -373,8 +372,9 @@ QSGNode* QskSkinlet::updateBackgroundNode(
if ( !gradient.isValid() )
return nullptr;
auto rectNode = QskSGNode::ensureNode< QskRectangleNode >( node );
rectNode->updateNode( rect, gradient );
auto rectNode = QskSGNode::ensureNode< QskBoxRectangleNode >( node );
rectNode->updateFilling( rect, QskBoxShapeMetrics(),
QskBoxBorderMetrics(), gradient );
return rectNode;
}

View File

@ -14,8 +14,12 @@ QSK_QT_PRIVATE_END
QSK_SUBCONTROL( QskTextInput, Panel )
QSK_SUBCONTROL( QskTextInput, Text )
#if 1
// shouldn't this be a Selected state, TODO ...
QSK_SUBCONTROL( QskTextInput, PanelSelected )
QSK_SUBCONTROL( QskTextInput, TextSelected )
#endif
QSK_SYSTEM_STATE( QskTextInput, ReadOnly, QskAspect::FirstSystemState << 1 )
QSK_SYSTEM_STATE( QskTextInput, Editing, QskAspect::FirstSystemState << 2 )
@ -458,6 +462,9 @@ void QskTextInput::focusInEvent( QFocusEvent* event )
break;
default:
#if 1
// auto selecting the complete text ???
#endif
setEditing( true );
}
}

View File

@ -1,95 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) The authors
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskBoxFillNode.h"
#include "QskGradientMaterial.h"
#include "QskGradient.h"
#include "QskGradientDirection.h"
#include "QskBoxShapeMetrics.h"
#include "QskBoxBorderMetrics.h"
#include "QskBoxRenderer.h"
#include "QskFillNodePrivate.h"
static inline QskHashValue qskMetricsHash(
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics )
{
QskHashValue hash = 13000;
hash = shape.hash( hash );
return borderMetrics.hash( hash );
}
class QskBoxFillNodePrivate final : public QskFillNodePrivate
{
public:
inline void resetValues()
{
rect = QRectF();
gradientHash = 0;
metricsHash = 0;
}
QRectF rect;
QskHashValue gradientHash = 0;
QskHashValue metricsHash = 0;
};
QskBoxFillNode::QskBoxFillNode()
: QskFillNode( *new QskBoxFillNodePrivate )
{
}
void QskBoxFillNode::updateNode( const QRectF& rect, const QskGradient& gradient )
{
updateNode( rect, QskBoxShapeMetrics(), QskBoxBorderMetrics(), gradient );
}
void QskBoxFillNode::updateNode(
const QRectF& rect, const QskBoxShapeMetrics& shapeMetrics,
const QskBoxBorderMetrics& borderMetrics, const QskGradient& gradient )
{
Q_D( QskBoxFillNode );
if ( rect.isEmpty() || !gradient.isVisible() )
{
d->resetValues();
resetGeometry();
return;
}
const auto metricsHash = qskMetricsHash( shapeMetrics, borderMetrics );
const auto gradientHash = gradient.hash( 22879 );
const bool dirtyColors = gradientHash != d->gradientHash;
const bool dirtyMetrics = ( metricsHash != d->metricsHash ) || ( rect != d->rect );
d->metricsHash = metricsHash;
d->gradientHash = gradientHash;
d->rect = rect;
if ( dirtyMetrics )
{
QskBoxRenderer::renderFillGeometry(
rect, shapeMetrics, borderMetrics, *geometry() );
markDirty( QSGNode::DirtyGeometry );
geometry()->markVertexDataDirty();
}
if ( gradient.isMonochrome() )
{
if ( dirtyColors )
setColoring( gradient.startColor().toRgb() );
}
else
{
// dirtyMetrics: the shader also depends on the target rectangle !
if ( dirtyColors || dirtyMetrics )
setColoring( rect, gradient.effectiveGradient() );
}
}

View File

@ -1,35 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) The authors
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_BOX_FILL_NODE_H
#define QSK_BOX_FILL_NODE_H
#include "QskGlobal.h"
#include "QskFillNode.h"
class QskGradient;
class QskBoxShapeMetrics;
class QskBoxBorderMetrics;
class QskBoxFillNodePrivate;
class QSK_EXPORT QskBoxFillNode : public QskFillNode
{
using Inherited = QskFillNode;
public:
QskBoxFillNode();
void updateNode( const QRectF&,
const QskBoxShapeMetrics&, const QskBoxBorderMetrics&,
const QskGradient& );
void updateNode( const QRectF&, const QskGradient& );
private:
Q_DECLARE_PRIVATE( QskBoxFillNode )
};
#endif

View File

@ -4,10 +4,8 @@
*****************************************************************************/
#include "QskBoxNode.h"
#include "QskBoxFillNode.h"
#include "QskBoxShadowNode.h"
#include "QskBoxRectangleNode.h"
#include "QskBoxRenderer.h"
#include "QskSGNode.h"
#include "QskGradient.h"
@ -67,7 +65,7 @@ void QskBoxNode::updateNode( const QRectF& rect,
QskBoxShadowNode* shadowNode = nullptr;
QskBoxRectangleNode* rectNode = nullptr;
QskBoxFillNode* fillNode = nullptr;
QskBoxRectangleNode* fillNode = nullptr;
if ( !shadowMetrics.isNull()
&& shadowColor.isValid() && shadowColor.alpha() != 0 )
@ -77,29 +75,23 @@ void QskBoxNode::updateNode( const QRectF& rect,
shape, shadowMetrics.blurRadius(), shadowColor );
}
/*
QskBoxRectangleNode is more efficient and creates batchable geometries.
So we prefer using it where possible.
Note, that the border is always done with a QskBoxRectangleNode
*/
if ( QskBoxRenderer::isGradientSupported( shape, gradient ) )
if ( QskBoxRectangleNode::isCombinedGeometrySupported( gradient ) )
{
rectNode = qskNode< QskBoxRectangleNode >( this, BoxRole );
rectNode->updateNode( rect, shape, borderMetrics, borderColors, gradient );
rectNode->updateBox( rect, shape, borderMetrics, borderColors, gradient );
}
else
{
if ( !borderMetrics.isNull() && borderColors.isVisible() )
{
rectNode = qskNode< QskBoxRectangleNode >( this, BoxRole );
rectNode->updateNode( rect, shape, borderMetrics, borderColors, QskGradient() );
rectNode->updateBorder( rect, shape, borderMetrics, borderColors );
}
if ( gradient.isVisible() )
{
fillNode = qskNode< QskBoxFillNode >( this, FillRole );
fillNode->updateNode( rect, shape, borderMetrics, gradient );
fillNode = qskNode< QskBoxRectangleNode >( this, FillRole );
fillNode->updateFilling( rect, shape, borderMetrics, gradient );
}
}

View File

@ -12,46 +12,55 @@
#include "QskGradientDirection.h"
#include "QskFillNodePrivate.h"
static inline QskHashValue qskMetricsHash(
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics )
{
QskHashValue hash = 13000;
hash = shape.hash( hash );
return borderMetrics.hash( hash );
}
static inline QskHashValue qskColorsHash(
const QskBoxBorderColors& borderColors, const QskGradient& fillGradient )
{
QskHashValue hash = 13000;
hash = borderColors.hash( hash );
return fillGradient.hash( hash );
}
#if 1
static inline QskGradient qskEffectiveGradient( const QskGradient& gradient )
{
auto g = gradient.effectiveGradient();
if ( g.type() != QskGradient::Linear )
{
qWarning() << "QskBoxRectangleNode does not support radial/conic gradients";
g.setDirection( QskGradient::Linear );
}
return g;
}
#endif
class QskBoxRectangleNodePrivate final : public QskFillNodePrivate
{
public:
QskHashValue metricsHash = 0;
QskHashValue colorsHash = 0;
QRectF rect;
inline void resetNode( QskBoxRectangleNode* node )
{
m_metricsHash = m_colorsHash = 0;
node->resetGeometry();
}
bool updateMetrics( const QRectF& rect,
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics )
{
QskHashValue hash = 13000;
hash = qHashBits( &rect, sizeof( rect ), hash );
hash = shape.hash( hash );
hash = borderMetrics.hash( hash );
return updateValue( m_metricsHash, hash );
}
bool updateColors( const QskBoxBorderColors& borderColors, const QskGradient& gradient )
{
QskHashValue hash = 13000;
if ( borderColors.isVisible() )
hash = borderColors.hash( hash );
if ( gradient.isVisible() )
hash = gradient.hash( hash );
return updateValue( m_colorsHash, hash );
}
private:
inline bool updateValue( QskHashValue& value, const QskHashValue newValue ) const
{
if ( newValue != value )
{
value = newValue;
return true;
}
return false;
}
public:
QskHashValue m_metricsHash = 0;
QskHashValue m_colorsHash = 0;
};
QskBoxRectangleNode::QskBoxRectangleNode()
@ -63,132 +72,163 @@ QskBoxRectangleNode::~QskBoxRectangleNode()
{
}
void QskBoxRectangleNode::updateNode(
const QRectF& rect, const QskGradient& fillGradient )
void QskBoxRectangleNode::updateFilling(
const QRectF& rect, const QskGradient& gradient )
{
updateNode( rect, QskBoxShapeMetrics(), QskBoxBorderMetrics(),
QskBoxBorderColors(), fillGradient );
updateFilling( rect, QskBoxShapeMetrics(), QskBoxBorderMetrics(), gradient );
}
void QskBoxRectangleNode::updateNode( const QRectF& rect,
const QskBoxShapeMetrics& shape, const QskGradient& fillGradient )
void QskBoxRectangleNode::updateFilling( const QRectF& rect,
const QskBoxShapeMetrics& shape, const QskGradient& gradient )
{
updateNode( rect, shape, QskBoxBorderMetrics(),
QskBoxBorderColors(), fillGradient );
updateFilling( rect, shape, QskBoxBorderMetrics(), gradient );
}
void QskBoxRectangleNode::updateNode( const QRectF& rect,
void QskBoxRectangleNode::updateFilling( const QRectF& rect,
const QskBoxShapeMetrics& shapeMetrics, const QskBoxBorderMetrics& borderMetrics,
const QskGradient& gradient )
{
Q_D( QskBoxRectangleNode );
if ( rect.isEmpty() || !gradient.isVisible() )
{
d->resetNode( this );
return;
}
const auto fillGradient = gradient.effectiveGradient();
const auto shape = shapeMetrics.toAbsolute( rect.size() );
const bool coloredGeometry = hasHint( PreferColoredGeometry )
&& QskBoxRenderer::isGradientSupported( fillGradient );
const bool dirtyMetrics = d->updateMetrics( rect, shape, borderMetrics );
const bool dirtyColors = d->updateColors( QskBoxBorderColors(), fillGradient )
&& ( coloredGeometry == isGeometryColored() );
if ( dirtyMetrics || dirtyColors )
{
if ( coloredGeometry )
{
setColoring( QskFillNode::Polychrome );
QskBoxRenderer::renderBox( rect, shape,
borderMetrics, QskBoxBorderColors(), fillGradient, *geometry() );
markDirty( QSGNode::DirtyGeometry );
}
else
{
if ( fillGradient.isMonochrome() )
{
if ( dirtyColors )
setColoring( fillGradient.rgbStart() );
}
else
{
// dirtyMetrics: the shader also depends on rect !
setColoring( rect, fillGradient );
}
if ( dirtyMetrics )
{
QskBoxRenderer::renderFillGeometry(
rect, shape, borderMetrics, *geometry() );
markDirty( QSGNode::DirtyGeometry );
}
}
}
}
void QskBoxRectangleNode::updateBorder( const QRectF& rect,
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics,
const QskBoxBorderColors& borderColors )
{
Q_D( QskBoxRectangleNode );
if ( rect.isEmpty() || borderMetrics.isNull() || !borderColors.isVisible() )
{
d->resetNode( this );
return;
}
const bool dirtyMetrics = d->updateMetrics( rect, shape, borderMetrics );
const bool dirtyColors = d->updateColors( borderColors, QskGradient() );
if ( dirtyMetrics || dirtyColors )
{
const auto coloring = QskFillNode::Polychrome;
if ( coloring == QskFillNode::Polychrome )
setColoring( coloring );
else
setColoring( borderColors.left().rgbStart() );
QskBoxRenderer::renderBox( rect, shape, borderMetrics,
borderColors, QskGradient(), *this->geometry() );
markDirty( QSGNode::DirtyGeometry );
}
}
void QskBoxRectangleNode::updateBox( const QRectF& rect,
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics,
const QskBoxBorderColors& borderColors, const QskGradient& gradient )
{
Q_D( QskBoxRectangleNode );
/*
We supports certain linear gradients only.
Everything else has to be done using QskRectangleNode
*/
const auto fillGradient = qskEffectiveGradient( gradient );
const auto metricsHash = qskMetricsHash( shape, borderMetrics );
const auto colorsHash = qskColorsHash( borderColors, fillGradient );
if ( ( metricsHash == d->metricsHash ) &&
( colorsHash == d->colorsHash ) && ( rect == d->rect ) )
{
return;
}
d->metricsHash = metricsHash;
d->colorsHash = colorsHash;
d->rect = rect;
markDirty( QSGNode::DirtyMaterial );
markDirty( QSGNode::DirtyGeometry );
if ( rect.isEmpty() )
{
resetGeometry();
d->resetNode( this );
return;
}
bool hasFill = fillGradient.isVisible();
bool hasBorder = !borderMetrics.isNull();
if ( hasBorder )
{
/*
Wrong as the border width should have an
effect - even if not being visible. TODO ...
*/
hasBorder = borderColors.isVisible();
}
if ( !hasBorder && !hasFill )
{
resetGeometry();
return;
}
const bool isFillMonochrome = hasFill ? fillGradient.isMonochrome() : true;
const bool isBorderMonochrome = hasBorder ? borderColors.isMonochrome() : true;
const bool hasFill = gradient.isVisible();
const bool hasBorder = !borderMetrics.isNull() && borderColors.isVisible();
if ( hasFill && hasBorder )
{
if ( isFillMonochrome && isBorderMonochrome )
{
if ( borderColors.left().rgbStart() == fillGradient.rgbStart() )
{
// we can draw border and background in one
hasBorder = false;
}
}
}
const bool dirtyMetrics = d->updateMetrics( rect, shape, borderMetrics );
const bool dirtyColors = d->updateColors( borderColors, gradient );
auto coloring = QskFillNode::Polychrome;
#if 0
if ( dirtyMetrics || dirtyColors )
{
/*
Always using the same material result in a better batching
but wastes some memory. when we have a solid color.
Maybe its worth to introduce a flag to control the behaviour,
but for the moment we go with performance.
For monochrome border/fiiling with the same color we might be
able to do QskFillNode::Monochrome. However this is not implemeted in
QskBoxRenderer yet. TODO ...
*/
setColoring( QskFillNode::Polychrome );
if ( !( hasFill && hasBorder ) )
auto fillGradient = gradient.effectiveGradient();
if ( !QskBoxRenderer::isGradientSupported( fillGradient ) )
{
if ( ( hasFill && isFillMonochrome )
|| ( hasBorder && !isBorderMonochrome )
{
coloring = QskFillNode::Monochrome;
qWarning() << "QskBoxRenderer does not support radial/conic gradients";
fillGradient.setDirection( QskGradient::Linear );
}
QskBoxRenderer::renderBox( rect, shape, borderMetrics,
borderColors, fillGradient, *geometry() );
markDirty( QSGNode::DirtyGeometry );
}
}
#endif
auto& geometry = *this->geometry();
if ( coloring == QskFillNode::Polychrome )
else if ( hasFill )
{
setColoring( coloring );
QskBoxRenderer::renderBox( d->rect, shape, borderMetrics,
borderColors, fillGradient, geometry );
updateFilling( rect, shape, borderMetrics, gradient );
}
else if ( hasBorder )
{
updateBorder( rect, shape, borderMetrics, borderColors );
}
else
{
if ( hasFill )
{
setColoring( fillGradient.rgbStart() );
QskBoxRenderer::renderFillGeometry(
d->rect, shape, QskBoxBorderMetrics(), geometry );
d->resetNode( this );
}
else
{
setColoring( borderColors.left().rgbStart() );
QskBoxRenderer::renderBorderGeometry(
d->rect, shape, borderMetrics, geometry );
}
}
geometry.markVertexDataDirty();
}
bool QskBoxRectangleNode::isCombinedGeometrySupported( const QskGradient& gradient )
{
return QskBoxRenderer::isGradientSupported( gradient );
}

View File

@ -24,15 +24,29 @@ class QSK_EXPORT QskBoxRectangleNode : public QskFillNode
QskBoxRectangleNode();
~QskBoxRectangleNode() override;
void updateNode( const QRectF&,
void updateBox( const QRectF&,
const QskBoxShapeMetrics&, const QskBoxBorderMetrics&,
const QskBoxBorderColors&, const QskGradient& );
void updateNode( const QRectF& rect, const QskGradient& );
void updateBorder( const QRectF&,
const QskBoxShapeMetrics&, const QskBoxBorderMetrics&,
const QskBoxBorderColors& );
void updateNode( const QRectF& rect,
void updateFilling( const QRectF& rect, const QskGradient& );
void updateFilling( const QRectF& rect,
const QskBoxShapeMetrics&, const QskGradient& );
void updateFilling( const QRectF& rect, const QskBoxShapeMetrics&,
const QskBoxBorderMetrics&, const QskGradient& );
/*
If true border/filling can be rendered together into the same geometry.
This should not make much difference as the scene graph batches geometries
for the same material anyway.
*/
static bool isCombinedGeometrySupported( const QskGradient& );
private:
Q_DECLARE_PRIVATE( QskBoxRectangleNode )
};

View File

@ -34,6 +34,9 @@ static inline QskVertex::ColoredLine* qskAllocateColoredLines(
static inline QskGradient qskEffectiveGradient(
const QRectF& rect, const QskGradient& gradient )
{
if ( !gradient.isVisible() )
return gradient;
const auto dir = gradient.linearDirection();
auto g = gradient;
@ -67,8 +70,7 @@ static inline bool qskMaybeSpreading( const QskGradient& gradient )
return true;
}
bool QskBoxRenderer::isGradientSupported(
const QskBoxShapeMetrics&, const QskGradient& gradient )
bool QskBoxRenderer::isGradientSupported( const QskGradient& gradient )
{
if ( !gradient.isVisible() || gradient.isMonochrome() )
return true;
@ -112,6 +114,7 @@ void QskBoxRenderer::renderBorderGeometry(
const QskBoxBorderMetrics& border, QSGGeometry& geometry )
{
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
geometry.markVertexDataDirty();
const QskBoxMetrics metrics( rect, shape, border );
const QskBoxBasicStroker stroker( metrics );
@ -132,6 +135,7 @@ void QskBoxRenderer::renderFillGeometry(
const QskBoxBorderMetrics& border, QSGGeometry& geometry )
{
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
geometry.markVertexDataDirty();
const QskBoxMetrics metrics( rect, shape, border );
QskBoxBasicStroker stroker( metrics );
@ -154,6 +158,7 @@ void QskBoxRenderer::renderBox( const QRectF& rect,
QSGGeometry& geometry )
{
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
geometry.markVertexDataDirty();
const QskBoxMetrics metrics( rect, shape, border );
const auto effectiveGradient = qskEffectiveGradient( metrics.innerRect, gradient );

View File

@ -39,7 +39,7 @@ namespace QskBoxRenderer
Filling the geometry usually with color information:
see QSGGeometry::defaultAttributes_ColoredPoint2D()
*/
QSK_EXPORT bool isGradientSupported( const QskBoxShapeMetrics&, const QskGradient& );
QSK_EXPORT bool isGradientSupported( const QskGradient& );
QSK_EXPORT void renderBox( const QRectF&,
const QskBoxShapeMetrics&, const QskBoxBorderMetrics&,

View File

@ -115,7 +115,7 @@ void QskFillNode::setColoring( Coloring coloring )
QskFillNode::Coloring QskFillNode::coloring() const
{
return d_func()->coloring;
return static_cast< QskFillNode::Coloring >( d_func()->coloring );
}
void QskFillNode::setColoring( const QColor& color )
@ -147,7 +147,34 @@ void QskFillNode::setColoring( const QRectF& rect, const QskGradient& gradient )
}
}
void QskFillNode::setHint( Hint hint, bool on )
{
Q_D( QskFillNode );
if ( on )
d->hints |= hint;
else
d->hints &= ~hint;
}
void QskFillNode::setHints( Hints hints )
{
d_func()->hints = hints;
}
QskFillNode::Hints QskFillNode::hints() const
{
return static_cast< QskFillNode::Hints >( d_func()->hints );
}
bool QskFillNode::hasHint( Hint hint ) const
{
return d_func()->hints & hint;
}
bool QskFillNode::isGeometryColored() const
{
return d_func()->geometry.attributeCount() != 1;
}
#include "moc_QskFillNode.cpp"

View File

@ -8,12 +8,15 @@
#include "QskGlobal.h"
#include <qsgnode.h>
#include <qcolor.h>
class QskFillNodePrivate;
class QskGradient;
class QSK_EXPORT QskFillNode : public QSGGeometryNode
{
Q_GADGET
using Inherited = QSGGeometryNode;
public:
@ -27,6 +30,28 @@ class QSK_EXPORT QskFillNode : public QSGGeometryNode
Conic
};
enum Hint
{
/*
Colors might be defined in the material ( QskGradientMaterial,
QSGFlatColorMaterial ) or attached to each point ( QSGVertexColorMaterial ).
The main advantage of using colored points is, that the material becomes
independent of the coloring and the scene graph is able to batch the nodes
( https://doc.qt.io/qt-6/qtquick-visualcanvas-scenegraph.html ).
However adding the color information for each point increases the memory
footprint.
The default setting is to use colored points where possible. Note, that
this is what is also done in the Qt/Quick code.
*/
PreferColoredGeometry = 1
};
Q_ENUM( Hint )
Q_DECLARE_FLAGS( Hints, Hint )
QskFillNode();
~QskFillNode() override;
@ -35,11 +60,20 @@ class QSK_EXPORT QskFillNode : public QSGGeometryNode
void setColoring( Coloring );
Coloring coloring() const;
void setColoring( QRgb );
void setColoring( const QColor& );
void setColoring( Qt::GlobalColor );
void setColoring( const QRectF&, const QskGradient& );
bool isGeometryColored() const;
void setHints( Hints );
Hints hints() const;
void setHint( Hint, bool on = true );
bool hasHint( Hint ) const;
protected:
QskFillNode( QskFillNodePrivate& );
@ -47,4 +81,14 @@ class QSK_EXPORT QskFillNode : public QSGGeometryNode
Q_DECLARE_PRIVATE( QskFillNode )
};
inline void QskFillNode::setColoring( QRgb rgb )
{
setColoring( QColor::fromRgba( rgb ) );
}
inline void QskFillNode::setColoring( Qt::GlobalColor color )
{
setColoring( QColor( color ) );
}
#endif

View File

@ -19,6 +19,8 @@ class QskFillNodePrivate : public QSGGeometryNodePrivate
public:
inline QskFillNodePrivate()
: geometry( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 )
, coloring( QskFillNode::Polychrome )
, hints( QskFillNode::PreferColoredGeometry )
{
}
@ -26,7 +28,9 @@ class QskFillNodePrivate : public QSGGeometryNodePrivate
friend class QskFillNode;
QSGGeometry geometry;
QskFillNode::Coloring coloring = QskFillNode::Polychrome;
uint coloring : 5;
uint hints : 3;
};
#endif

View File

@ -1,105 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) The authors
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskRectangleNode.h"
#include "QskGradient.h"
#include "QskBoxRenderer.h"
#include "QskBoxShapeMetrics.h"
#include "QskFillNodePrivate.h"
class QskRectangleNodePrivate final : public QskFillNodePrivate
{
public:
inline void resetValues()
{
rect = QRectF();
shape = QskBoxShapeMetrics();
gradientHash = 0;
metricsHash = 0;
}
QRectF rect;
QskBoxShapeMetrics shape;
QskHashValue gradientHash = 0;
QskHashValue metricsHash = 0;
};
QskRectangleNode::QskRectangleNode()
: QskFillNode( *new QskRectangleNodePrivate )
{
}
QskRectangleNode::~QskRectangleNode()
{
}
void QskRectangleNode::updateNode(
const QRectF& rect, const QskGradient& gradient )
{
updateNode( rect, QskBoxShapeMetrics(), gradient );
}
void QskRectangleNode::updateNode(
const QRectF& rect, const QskBoxShapeMetrics& shape, const QskGradient& gradient )
{
Q_D( QskRectangleNode );
if ( rect.isEmpty() || !gradient.isVisible() )
{
d->resetValues();
resetGeometry();
return;
}
const auto effectiveGradient = gradient.effectiveGradient();
const auto effectiveShape = shape.toAbsolute( rect.size() );
const auto gradientHash = effectiveGradient.hash( 54228 );
const auto metricsHash = effectiveShape.hash( 44564 );
const bool dirtyColors = gradientHash != d->gradientHash;
const bool dirtyMetrics = ( rect != d->rect ) || ( metricsHash != d->metricsHash );
if ( !( dirtyColors || dirtyMetrics ) )
return;
d->gradientHash = gradientHash;
d->metricsHash = metricsHash;
d->rect = rect;
d->shape = effectiveShape;
if ( QskBoxRenderer::isGradientSupported( effectiveShape, effectiveGradient ) )
{
setColoring( Polychrome );
/*
Colors are added to the vertices, while the material does
not depend on the gradient at all
*/
if ( dirtyMetrics || dirtyColors )
{
QskBoxRenderer::renderBox( rect,
effectiveShape, effectiveGradient, *geometry() );
geometry()->markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
}
}
else
{
if ( dirtyColors || dirtyMetrics )
setColoring( rect, effectiveGradient );
if ( dirtyMetrics )
{
QskBoxRenderer::renderFillGeometry( rect, effectiveShape, *geometry() );
geometry()->markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
}
}
}

View File

@ -1,34 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) The authors
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_RECTANGLE_NODE_H
#define QSK_RECTANGLE_NODE_H
#include "QskGlobal.h"
#include "QskFillNode.h"
class QskGradient;
class QskBoxShapeMetrics;
class QskRectangleNodePrivate;
/*
QskRectangleNode is for rounded rectangles without a border.
*/
class QSK_EXPORT QskRectangleNode : public QskFillNode
{
using Inherited = QskFillNode;
public:
QskRectangleNode();
~QskRectangleNode() override;
void updateNode( const QRectF&, const QskGradient& );
void updateNode( const QRectF&, const QskBoxShapeMetrics&, const QskGradient& );
private:
Q_DECLARE_PRIVATE( QskRectangleNode )
};
#endif