Merge branch 'master' into features/modelobjectbinder
This commit is contained in:
commit
69eae90d3a
|
@ -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()
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
};
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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&,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue