2017-07-21 18:21:34 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskBoxNode.h"
|
2018-08-03 08:15:28 +02:00
|
|
|
#include "QskBoxBorderColors.h"
|
|
|
|
#include "QskBoxBorderMetrics.h"
|
2017-10-17 17:34:00 +02:00
|
|
|
#include "QskBoxRenderer.h"
|
2017-10-20 13:09:30 +02:00
|
|
|
#include "QskBoxShapeMetrics.h"
|
|
|
|
#include "QskGradient.h"
|
|
|
|
|
2018-07-19 14:10:48 +02:00
|
|
|
#include <qglobalstatic.h>
|
2018-08-03 08:15:28 +02:00
|
|
|
#include <qsgflatcolormaterial.h>
|
|
|
|
#include <qsgvertexcolormaterial.h>
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2022-03-23 15:39:17 +01:00
|
|
|
QSK_QT_PRIVATE_BEGIN
|
|
|
|
#include <private/qsgnode_p.h>
|
|
|
|
QSK_QT_PRIVATE_END
|
|
|
|
|
2017-10-30 14:38:30 +01:00
|
|
|
Q_GLOBAL_STATIC( QSGVertexColorMaterial, qskMaterialVertex )
|
2017-08-28 17:42:11 +02:00
|
|
|
|
2022-03-25 10:28:06 +01:00
|
|
|
static inline QskHashValue qskMetricsHash(
|
2018-08-03 08:15:28 +02:00
|
|
|
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics )
|
2017-10-17 17:34:00 +02:00
|
|
|
{
|
2022-03-25 10:28:06 +01:00
|
|
|
QskHashValue hash = 13000;
|
2017-09-03 14:55:21 +02:00
|
|
|
|
2017-10-20 13:09:30 +02:00
|
|
|
hash = shape.hash( hash );
|
|
|
|
return borderMetrics.hash( hash );
|
2017-08-28 17:42:11 +02:00
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2022-03-25 10:28:06 +01:00
|
|
|
static inline QskHashValue qskColorsHash(
|
2018-08-03 08:15:28 +02:00
|
|
|
const QskBoxBorderColors& borderColors, const QskGradient& fillGradient )
|
2017-08-28 17:42:11 +02:00
|
|
|
{
|
2022-03-25 10:28:06 +01:00
|
|
|
QskHashValue hash = 13000;
|
2017-10-20 13:09:30 +02:00
|
|
|
hash = borderColors.hash( hash );
|
|
|
|
return fillGradient.hash( hash );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2022-03-23 15:39:17 +01:00
|
|
|
class QskBoxNodePrivate final : public QSGGeometryNodePrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
QskBoxNodePrivate()
|
|
|
|
: geometry( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-03-25 10:28:06 +01:00
|
|
|
QskHashValue metricsHash = 0;
|
|
|
|
QskHashValue colorsHash = 0;
|
2022-03-23 15:39:17 +01:00
|
|
|
QRectF rect;
|
|
|
|
|
|
|
|
QSGGeometry geometry;
|
|
|
|
};
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
QskBoxNode::QskBoxNode()
|
2022-03-23 15:39:17 +01:00
|
|
|
: QSGGeometryNode( *new QskBoxNodePrivate )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2022-03-23 15:39:17 +01:00
|
|
|
Q_D( QskBoxNode );
|
|
|
|
|
2017-10-30 14:38:30 +01:00
|
|
|
setMaterial( qskMaterialVertex );
|
2022-03-23 15:39:17 +01:00
|
|
|
setGeometry( &d->geometry );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QskBoxNode::~QskBoxNode()
|
|
|
|
{
|
2017-10-30 14:38:30 +01:00
|
|
|
if ( material() != qskMaterialVertex )
|
2017-10-17 17:34:00 +02:00
|
|
|
delete material();
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2017-10-20 13:09:30 +02:00
|
|
|
void QskBoxNode::setBoxData( const QRectF& rect, const QskGradient& fillGradient )
|
|
|
|
{
|
|
|
|
setBoxData( rect, QskBoxShapeMetrics(), QskBoxBorderMetrics(),
|
|
|
|
QskBoxBorderColors(), fillGradient );
|
|
|
|
}
|
|
|
|
|
2019-01-04 13:42:16 +01:00
|
|
|
void QskBoxNode::setBoxData( const QRectF& rect,
|
2017-10-20 13:09:30 +02:00
|
|
|
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics,
|
2021-10-25 08:29:12 +02:00
|
|
|
const QskBoxBorderColors& borderColors, const QskGradient& gradient )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2022-03-23 15:39:17 +01:00
|
|
|
Q_D( QskBoxNode );
|
|
|
|
|
2021-10-25 08:29:12 +02:00
|
|
|
QskGradient fillGradient = gradient;
|
|
|
|
#if 1
|
|
|
|
// Renderer is buggy for monochrome gradients with stops. TODO ...
|
|
|
|
if ( fillGradient.stops().count() > 2 && fillGradient.isMonochrome() )
|
|
|
|
{
|
|
|
|
fillGradient.setColor( fillGradient.startColor() );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-10-17 17:34:00 +02:00
|
|
|
#if 1
|
2022-03-25 10:28:06 +01:00
|
|
|
const auto metricsHash = qskMetricsHash( shape, borderMetrics );
|
|
|
|
const auto colorsHash = qskColorsHash( borderColors, fillGradient );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2022-03-23 15:39:17 +01:00
|
|
|
if ( ( metricsHash == d->metricsHash ) &&
|
|
|
|
( colorsHash == d->colorsHash ) && ( rect == d->rect ) )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-17 17:34:00 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-23 15:39:17 +01:00
|
|
|
d->metricsHash = metricsHash;
|
|
|
|
d->colorsHash = colorsHash;
|
|
|
|
d->rect = rect;
|
2017-10-17 17:34:00 +02:00
|
|
|
|
|
|
|
markDirty( QSGNode::DirtyMaterial );
|
|
|
|
markDirty( QSGNode::DirtyGeometry );
|
2017-07-21 18:21:34 +02:00
|
|
|
#endif
|
2017-10-17 17:34:00 +02:00
|
|
|
|
|
|
|
if ( rect.isEmpty() )
|
|
|
|
{
|
2022-03-23 15:39:17 +01:00
|
|
|
d->geometry.allocate( 0 );
|
2017-10-17 17:34:00 +02:00
|
|
|
return;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2017-10-20 13:09:30 +02:00
|
|
|
bool hasFill = fillGradient.isValid();
|
2017-10-17 17:34:00 +02:00
|
|
|
|
|
|
|
bool hasBorder = !borderMetrics.isNull();
|
|
|
|
if ( hasBorder )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-17 17:34:00 +02:00
|
|
|
/*
|
|
|
|
Wrong as the border width should have an
|
|
|
|
effect - even if not being visible. TODO ...
|
|
|
|
*/
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-10-17 17:34:00 +02:00
|
|
|
hasBorder = borderColors.isVisible();
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-10-17 17:34:00 +02:00
|
|
|
if ( !hasBorder && !hasFill )
|
|
|
|
{
|
2022-03-23 15:39:17 +01:00
|
|
|
d->geometry.allocate( 0 );
|
2017-10-17 17:34:00 +02:00
|
|
|
return;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2017-10-20 13:09:30 +02:00
|
|
|
const bool isFillMonochrome = hasFill ? fillGradient.isMonochrome() : true;
|
2017-10-17 17:34:00 +02:00
|
|
|
const bool isBorderMonochrome = hasBorder ? borderColors.isMonochrome() : true;
|
|
|
|
|
|
|
|
if ( hasFill && hasBorder )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-17 17:34:00 +02:00
|
|
|
if ( isFillMonochrome && isBorderMonochrome )
|
|
|
|
{
|
2022-04-16 16:01:40 +02:00
|
|
|
if ( borderColors.left().startColor() == fillGradient.startColor() )
|
2017-10-17 17:34:00 +02:00
|
|
|
{
|
|
|
|
// we can draw border and background in one
|
|
|
|
hasBorder = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-08-28 17:42:11 +02:00
|
|
|
|
2021-07-12 08:26:04 +02:00
|
|
|
#if 0
|
2017-10-17 17:34:00 +02:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2021-07-12 08:26:04 +02:00
|
|
|
bool maybeFlat = true;
|
|
|
|
|
2017-10-17 17:34:00 +02:00
|
|
|
if ( maybeFlat )
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
if ( ( hasFill && hasBorder ) ||
|
|
|
|
( hasFill && !isFillMonochrome ) ||
|
|
|
|
( hasBorder && !isBorderMonochrome ) )
|
2017-10-17 17:34:00 +02:00
|
|
|
{
|
|
|
|
maybeFlat = false;
|
|
|
|
}
|
|
|
|
}
|
2021-07-12 08:26:04 +02:00
|
|
|
#else
|
|
|
|
bool maybeFlat = false;
|
|
|
|
#endif
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-10-17 17:34:00 +02:00
|
|
|
QskBoxRenderer renderer;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-10-17 17:34:00 +02:00
|
|
|
if ( !maybeFlat )
|
|
|
|
{
|
|
|
|
setMonochrome( false );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2022-03-23 15:39:17 +01:00
|
|
|
renderer.renderBox( d->rect, shape, borderMetrics,
|
2017-10-20 13:09:30 +02:00
|
|
|
borderColors, fillGradient, *geometry() );
|
2017-10-17 17:34:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// all is done with one color
|
|
|
|
setMonochrome( true );
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
auto* flatMaterial = static_cast< QSGFlatColorMaterial* >( material() );
|
2017-10-17 17:34:00 +02:00
|
|
|
|
|
|
|
if ( hasFill )
|
|
|
|
{
|
2017-10-20 13:09:30 +02:00
|
|
|
flatMaterial->setColor( fillGradient.startColor() );
|
2022-03-23 15:39:17 +01:00
|
|
|
renderer.renderFill( d->rect, shape, QskBoxBorderMetrics(), *geometry() );
|
2017-10-17 17:34:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-04-16 16:01:40 +02:00
|
|
|
flatMaterial->setColor( borderColors.left().startColor().rgba() );
|
2022-03-23 15:39:17 +01:00
|
|
|
renderer.renderBorder( d->rect, shape, borderMetrics, *geometry() );
|
2017-10-17 17:34:00 +02:00
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-17 17:34:00 +02:00
|
|
|
void QskBoxNode::setMonochrome( bool on )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-17 17:34:00 +02:00
|
|
|
const auto material = this->material();
|
|
|
|
|
2017-10-30 14:38:30 +01:00
|
|
|
if ( on == ( material != qskMaterialVertex ) )
|
2017-10-17 17:34:00 +02:00
|
|
|
return;
|
|
|
|
|
2022-03-23 15:39:17 +01:00
|
|
|
Q_D( QskBoxNode );
|
|
|
|
|
|
|
|
d->geometry.allocate( 0 );
|
2017-10-17 17:34:00 +02:00
|
|
|
|
|
|
|
if ( on )
|
|
|
|
{
|
|
|
|
setMaterial( new QSGFlatColorMaterial() );
|
|
|
|
|
|
|
|
const QSGGeometry g( QSGGeometry::defaultAttributes_Point2D(), 0 );
|
2022-03-23 15:39:17 +01:00
|
|
|
memcpy( ( void* ) &d->geometry, ( void* ) &g, sizeof( QSGGeometry ) );
|
2017-10-17 17:34:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-10-30 14:38:30 +01:00
|
|
|
setMaterial( qskMaterialVertex );
|
2017-10-17 17:34:00 +02:00
|
|
|
delete material;
|
|
|
|
|
|
|
|
const QSGGeometry g( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 );
|
2022-03-23 15:39:17 +01:00
|
|
|
memcpy( ( void* ) &d->geometry, ( void* ) &g, sizeof( QSGGeometry ) );
|
2017-10-17 17:34:00 +02:00
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|