full support of all linear gradient vectors by QskRectRenderer ( = not rounded rectangles ).
This commit is contained in:
parent
3ce2cea547
commit
8c6f0ffd60
@ -45,12 +45,20 @@ namespace
|
||||
}
|
||||
|
||||
QskGradient gradient;
|
||||
#if 1
|
||||
gradient.setLinearDirection( 0.0, 0.0, 1.0, 1.0 );
|
||||
#if 0
|
||||
gradient.setLinearDirection( 0.0, 1.0, 1.0, 0.0 );
|
||||
#endif
|
||||
#if 0
|
||||
gradient.setLinearDirection( 1.0, 1.0, 0.0, 0.0 );
|
||||
#endif
|
||||
#if 1
|
||||
gradient.setLinearDirection( 0.2, 0.2, 0.7, 0.5 );
|
||||
gradient.setSpreadMode( QskGradient::PadSpread );
|
||||
#endif
|
||||
#if 0
|
||||
gradient.setLinearDirection( -0.2, -0.1, 1.2, 1.3 );
|
||||
#endif
|
||||
#if 0
|
||||
gradient.setLinearDirection( 0.5, -0.5, 0.5, 1.5 );
|
||||
#endif
|
||||
#if 0
|
||||
gradient.setRadialDirection( 0.25, 0.75, 0.25, 0.0 );
|
||||
@ -88,7 +96,7 @@ int main( int argc, char** argv )
|
||||
|
||||
QskWindow window;
|
||||
window.addItem( new MainView() );
|
||||
window.resize( 600, 600 );
|
||||
window.resize( 800, 600 );
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
|
@ -44,19 +44,7 @@ static inline QskGradient qskEffectiveGradient( const QskGradient& gradient )
|
||||
{
|
||||
auto g = gradient.effectiveGradient();
|
||||
|
||||
if ( g.type() == QskGradient::Linear )
|
||||
{
|
||||
auto dir = g.linearDirection();
|
||||
|
||||
if ( dir.isTilted() )
|
||||
{
|
||||
dir.setStart( 0.0, 0.0 );
|
||||
dir.setStop( 1.0, 1.0 );
|
||||
|
||||
g.setLinearDirection( dir );
|
||||
}
|
||||
}
|
||||
else
|
||||
if ( g.type() != QskGradient::Linear )
|
||||
{
|
||||
qWarning() << "QskBoxRectangleNode does not support radial/conic gradients";
|
||||
g.setDirection( QskGradient::Linear );
|
||||
|
@ -4,6 +4,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskBoxRenderer.h"
|
||||
#include "QskRectRenderer.h"
|
||||
#include "QskRoundedRectRenderer.h"
|
||||
#include "QskBoxShapeMetrics.h"
|
||||
|
||||
#include "QskGradient.h"
|
||||
@ -14,9 +16,9 @@ void QskBoxRenderer::renderBorder(
|
||||
const QskBoxBorderMetrics& border, QSGGeometry& geometry )
|
||||
{
|
||||
if ( shape.isRectangle() )
|
||||
renderRectBorder( rect, border, geometry );
|
||||
QskRectRenderer::renderBorder( rect, border, geometry );
|
||||
else
|
||||
renderRectellipseBorder( rect, shape, border, geometry );
|
||||
QskRoundedRectRenderer::renderRectellipseBorder( rect, shape, border, geometry );
|
||||
}
|
||||
|
||||
void QskBoxRenderer::renderFill(
|
||||
@ -24,9 +26,9 @@ void QskBoxRenderer::renderFill(
|
||||
const QskBoxBorderMetrics& border, QSGGeometry& geometry )
|
||||
{
|
||||
if ( shape.isRectangle() )
|
||||
renderRectFill( rect, border, geometry );
|
||||
QskRectRenderer::renderFill( rect, border, geometry );
|
||||
else
|
||||
renderRectellipseFill( rect, shape, border, geometry );
|
||||
QskRoundedRectRenderer::renderRectellipseFill( rect, shape, border, geometry );
|
||||
}
|
||||
|
||||
void QskBoxRenderer::renderBox( const QRectF& rect,
|
||||
@ -35,39 +37,68 @@ void QskBoxRenderer::renderBox( const QRectF& rect,
|
||||
QSGGeometry& geometry )
|
||||
{
|
||||
if ( shape.isRectangle() )
|
||||
renderRect( rect, border, borderColors, gradient, geometry );
|
||||
{
|
||||
QskRectRenderer::renderRect(
|
||||
rect, border, borderColors, gradient, geometry );
|
||||
}
|
||||
else
|
||||
renderRectellipse( rect, shape, border, borderColors, gradient, geometry );
|
||||
{
|
||||
QskRoundedRectRenderer::renderRectellipse(
|
||||
rect, shape, border, borderColors, gradient, geometry );
|
||||
}
|
||||
}
|
||||
|
||||
bool QskBoxRenderer::isGradientSupported(
|
||||
const QskBoxShapeMetrics&, const QskGradient& gradient )
|
||||
{
|
||||
if ( !gradient.isVisible() || gradient.isMonochrome()
|
||||
|| ( gradient.type() == QskGradient::Stops ) )
|
||||
const QskBoxShapeMetrics& shape, const QskGradient& gradient )
|
||||
{
|
||||
if ( !gradient.isVisible() || gradient.isMonochrome() )
|
||||
return true;
|
||||
|
||||
if ( gradient.spreadMode() != QskGradient::PadSpread )
|
||||
{
|
||||
// Only true if the situation requires spreading TODO ...
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( gradient.type() == QskGradient::Linear )
|
||||
switch( gradient.type() )
|
||||
{
|
||||
const auto dir = gradient.linearDirection();
|
||||
|
||||
if ( dir.isTilted() )
|
||||
{
|
||||
if ( dir.x1() == 0.0 && dir.y1() == 0.0
|
||||
&& dir.x2() == 1.0 && dir.y2() == 1.0 )
|
||||
case QskGradient::Stops:
|
||||
{
|
||||
// will be rendered as vertical linear gradient
|
||||
return true;
|
||||
}
|
||||
case QskGradient::Linear:
|
||||
{
|
||||
if ( shape.isRectangle() )
|
||||
{
|
||||
// rectangles are fully supported
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( dir.x1() == 0.0 && dir.x2() == 1.0 )
|
||||
return true;
|
||||
/*
|
||||
For rounded rectangles we currently support
|
||||
only the most common use cases. TODO ...
|
||||
*/
|
||||
|
||||
if ( dir.y1() == 0.0 && dir.y2() == 1.0 )
|
||||
return true;
|
||||
const auto dir = gradient.linearDirection();
|
||||
if ( dir.isTilted() )
|
||||
{
|
||||
return ( dir.x1() == 0.0 && dir.x2() == 0.0 )
|
||||
&& ( dir.y1() == 1.0 && dir.y2() == 1.0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
return ( dir.x1() == 0.0 && dir.x2() == 1.0 )
|
||||
|| ( dir.y1() == 0.0 && dir.y2() == 1.0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// Radial/Conical gradients have to be done with QskGradientMaterial
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,15 +59,6 @@ class QSK_EXPORT QskBoxRenderer
|
||||
};
|
||||
|
||||
private:
|
||||
static void renderRectFill( const QRectF&,
|
||||
const QskBoxBorderMetrics&, QSGGeometry& );
|
||||
|
||||
static void renderRectBorder( const QRectF&,
|
||||
const QskBoxBorderMetrics&, QSGGeometry& );
|
||||
|
||||
static void renderRect( const QRectF&, const QskBoxBorderMetrics&,
|
||||
const QskBoxBorderColors&, const QskGradient&, QSGGeometry& );
|
||||
|
||||
static void renderRectellipseFill( const QRectF&,
|
||||
const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, QSGGeometry& );
|
||||
|
||||
@ -80,9 +71,6 @@ class QSK_EXPORT QskBoxRenderer
|
||||
|
||||
static void renderDiagonalFill( const Metrics&, const QskGradient&,
|
||||
int lineCount, QskVertex::ColoredLine* );
|
||||
|
||||
static void renderRectFill( const QskVertex::Quad&,
|
||||
const QskGradient&, QskVertex::ColoredLine* );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -88,72 +88,11 @@ namespace QskVertex
|
||||
}
|
||||
};
|
||||
|
||||
class SolidColorIterator : public ColorIterator
|
||||
{
|
||||
public:
|
||||
inline SolidColorIterator( const QColor& color )
|
||||
: m_color( color )
|
||||
{
|
||||
}
|
||||
|
||||
inline Color colorAt( qreal ) const
|
||||
{
|
||||
return m_color;
|
||||
}
|
||||
|
||||
private:
|
||||
const Color m_color;
|
||||
};
|
||||
|
||||
class TwoColorIterator01 : public ColorIterator
|
||||
{
|
||||
public:
|
||||
inline TwoColorIterator01( const QColor& color1, const QColor& color2 )
|
||||
: m_color1( color1 )
|
||||
, m_color2( color2 )
|
||||
{
|
||||
}
|
||||
|
||||
inline Color colorAt( qreal value ) const
|
||||
{
|
||||
return m_color1.interpolatedTo( m_color2, value );
|
||||
}
|
||||
|
||||
private:
|
||||
const Color m_color1, m_color2;
|
||||
};
|
||||
|
||||
class TwoColorIterator : public ColorIterator
|
||||
{
|
||||
public:
|
||||
inline TwoColorIterator( qreal value1, qreal value2,
|
||||
const QColor& color1, const QColor& color2 )
|
||||
: m_value1( value1 )
|
||||
, m_range( value2 - value1 )
|
||||
, m_color1( color1 )
|
||||
, m_color2( color2 )
|
||||
{
|
||||
}
|
||||
|
||||
inline Color colorAt( qreal value ) const
|
||||
{
|
||||
const qreal r = ( value - m_value1 ) / m_range;
|
||||
return m_color1.interpolatedTo( m_color2, r );
|
||||
}
|
||||
|
||||
private:
|
||||
const qreal m_value1, m_range;
|
||||
const Color m_color1, m_color2;
|
||||
};
|
||||
|
||||
class GradientColorIterator : public ColorIterator
|
||||
{
|
||||
public:
|
||||
inline GradientColorIterator( qreal value1, qreal value2,
|
||||
const QskGradientStops& stops )
|
||||
: m_value1( value1 )
|
||||
, m_value2( value2 )
|
||||
, m_stops( stops )
|
||||
inline GradientColorIterator( const QskGradientStops& stops )
|
||||
: m_stops( stops )
|
||||
{
|
||||
if ( stops.first().position() > 0.0 )
|
||||
{
|
||||
@ -171,8 +110,8 @@ namespace QskVertex
|
||||
if ( stops.last().position() < 1.0 )
|
||||
m_finalIndex++;
|
||||
|
||||
m_valueStep1 = value1;
|
||||
m_valueStep2 = valueAt( stops[ m_index ].position() );
|
||||
m_valueStep1 = 0.0;
|
||||
m_valueStep2 = stops[ m_index ].position();
|
||||
m_stepSize = m_valueStep2 - m_valueStep1;
|
||||
}
|
||||
|
||||
@ -202,14 +141,14 @@ namespace QskVertex
|
||||
if ( m_index >= m_stops.count() )
|
||||
{
|
||||
m_color2 = m_color1;
|
||||
m_valueStep2 = valueAt( 1.0 );
|
||||
m_valueStep2 = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& stop = m_stops[ m_index ];
|
||||
|
||||
m_color2 = stop.rgb();
|
||||
m_valueStep2 = valueAt( stop.position() );
|
||||
m_valueStep2 = stop.position();
|
||||
}
|
||||
|
||||
m_stepSize = m_valueStep2 - m_valueStep1;
|
||||
@ -223,12 +162,6 @@ namespace QskVertex
|
||||
}
|
||||
|
||||
private:
|
||||
inline qreal valueAt( qreal pos ) const
|
||||
{
|
||||
return m_value1 + pos * ( ( m_value2 - m_value1 ) );
|
||||
}
|
||||
|
||||
const qreal m_value1, m_value2;
|
||||
const QskGradientStops m_stops;
|
||||
|
||||
int m_index, m_finalIndex;
|
||||
@ -244,11 +177,14 @@ namespace QskVertex
|
||||
{
|
||||
while ( !colorIt.isDone() && ( colorIt.value() < contourIt.value() ) )
|
||||
{
|
||||
contourIt.setGradientLine( colorIt, line++ );
|
||||
if ( contourIt.setGradientLine( colorIt.value(), colorIt.color(), line ) )
|
||||
line++;
|
||||
|
||||
colorIt.advance();
|
||||
}
|
||||
|
||||
contourIt.setContourLine( colorIt, line++ );
|
||||
const auto color = colorIt.colorAt( contourIt.value() );
|
||||
contourIt.setContourLine( color, line++ );
|
||||
|
||||
} while ( contourIt.advance() );
|
||||
|
||||
@ -257,26 +193,16 @@ namespace QskVertex
|
||||
|
||||
template< class ContourIterator >
|
||||
ColoredLine* fillOrdered( ContourIterator& contourIt,
|
||||
qreal value1, qreal value2, const QskGradient& gradient, ColoredLine* line )
|
||||
const QskGradient& gradient, ColoredLine* line )
|
||||
{
|
||||
if ( gradient.stepCount() == 1 )
|
||||
{
|
||||
if ( value2 == 1.0 && value1 == 0.0 )
|
||||
{
|
||||
TwoColorIterator01 colorIt( gradient.rgbStart(), gradient.rgbEnd() );
|
||||
GradientColorIterator colorIt( gradient.stops() );
|
||||
line = fillOrdered( contourIt, colorIt, line );
|
||||
}
|
||||
else
|
||||
{
|
||||
TwoColorIterator colorIt( value1, value2,
|
||||
gradient.rgbStart(), gradient.rgbEnd() );
|
||||
|
||||
line = fillOrdered( contourIt, colorIt, line );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GradientColorIterator colorIt( value1, value2, gradient.stops() );
|
||||
GradientColorIterator colorIt( gradient.stops() );
|
||||
line = fillOrdered( contourIt, colorIt, line );
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskBoxRenderer.h"
|
||||
#include "QskRoundedRectRenderer.h"
|
||||
#include "QskBoxRendererColorMap.h"
|
||||
#include "QskGradient.h"
|
||||
#include "QskVertex.h"
|
||||
@ -44,7 +44,7 @@ namespace
|
||||
class ValueCurve
|
||||
{
|
||||
public:
|
||||
ValueCurve( const QskBoxRenderer::Metrics& m )
|
||||
ValueCurve( const QskRoundedRectRenderer::Metrics& m )
|
||||
{
|
||||
/*
|
||||
The slopes of the value line and those for the fill lines.
|
||||
@ -127,7 +127,7 @@ namespace
|
||||
{
|
||||
}
|
||||
|
||||
void setup( const QskBoxRenderer::Metrics& metrics,
|
||||
void setup( const QskRoundedRectRenderer::Metrics& metrics,
|
||||
bool isLeading, bool clockwise,
|
||||
qreal cos, qreal cosStep, qreal sin, qreal sinStep,
|
||||
qreal x1, qreal y1, qreal v1, qreal x2, qreal y2, qreal v2 )
|
||||
@ -167,7 +167,9 @@ namespace
|
||||
|
||||
inline const ContourLine& contourLine() const { return m_contourLine; }
|
||||
|
||||
inline void advance( const QskBoxRenderer::Metrics& metrics, const ValueCurve& curve )
|
||||
inline void advance(
|
||||
const QskRoundedRectRenderer::Metrics& metrics,
|
||||
const ValueCurve& curve )
|
||||
{
|
||||
if ( m_isDone )
|
||||
return;
|
||||
@ -318,7 +320,7 @@ namespace
|
||||
static constexpr qreal m_eps = 1e-4;
|
||||
|
||||
inline void setCorner(
|
||||
Qt::Corner corner, const QskBoxRenderer::Metrics& metrics )
|
||||
Qt::Corner corner, const QskRoundedRectRenderer::Metrics& metrics )
|
||||
{
|
||||
m_corner = corner;
|
||||
const auto& c = metrics.corner[ corner ];
|
||||
@ -412,7 +414,7 @@ namespace
|
||||
class OutlineIterator
|
||||
{
|
||||
public:
|
||||
OutlineIterator( const QskBoxRenderer::Metrics& metrics,
|
||||
OutlineIterator( const QskRoundedRectRenderer::Metrics& metrics,
|
||||
const ValueCurve& curve, bool clockwise )
|
||||
: m_metrics( metrics )
|
||||
, m_curve( curve )
|
||||
@ -549,7 +551,7 @@ namespace
|
||||
line->setLine( x1, y1, x2, y2, color );
|
||||
}
|
||||
|
||||
const QskBoxRenderer::Metrics& m_metrics;
|
||||
const QskRoundedRectRenderer::Metrics& m_metrics;
|
||||
const ValueCurve& m_curve;
|
||||
|
||||
/*
|
||||
@ -564,23 +566,23 @@ namespace
|
||||
{
|
||||
public:
|
||||
DRectellipseIterator(
|
||||
const QskBoxRenderer::Metrics& metrics, const ValueCurve& curve )
|
||||
const QskRoundedRectRenderer::Metrics& metrics,
|
||||
const ValueCurve& curve )
|
||||
: m_left( metrics, curve, false )
|
||||
, m_right( metrics, curve, true )
|
||||
{
|
||||
m_next = ( m_left.value() < m_right.value() ) ? &m_left : &m_right;
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setGradientLine( const ColorIterator& it, ColoredLine* line )
|
||||
inline bool setGradientLine( qreal value, Color color, ColoredLine* line )
|
||||
{
|
||||
m_next->setLineAt( it.value(), it.color(), line );
|
||||
m_next->setLineAt( value, color, line );
|
||||
return true;
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setContourLine( const ColorIterator& it, ColoredLine* line )
|
||||
inline void setContourLine( Color color, ColoredLine* line )
|
||||
{
|
||||
m_next->setLine( it.colorAt( m_next->value() ), line );
|
||||
m_next->setLine( color, line );
|
||||
}
|
||||
|
||||
inline qreal value() const
|
||||
@ -602,13 +604,13 @@ namespace
|
||||
};
|
||||
}
|
||||
|
||||
void QskBoxRenderer::renderDiagonalFill( const QskBoxRenderer::Metrics& metrics,
|
||||
void QskRoundedRectRenderer::renderDiagonalFill( const QskRoundedRectRenderer::Metrics& metrics,
|
||||
const QskGradient& gradient, int fillLineCount, QskVertex::ColoredLine* lines )
|
||||
{
|
||||
const ValueCurve curve( metrics );
|
||||
|
||||
DRectellipseIterator it( metrics, curve );
|
||||
auto line = QskVertex::fillOrdered( it, 0.0, 1.0, gradient, lines );
|
||||
auto line = QskVertex::fillOrdered( it, gradient, lines );
|
||||
|
||||
/*
|
||||
There are a couple of reasons, why less points have been rendered
|
||||
|
@ -1,654 +0,0 @@
|
||||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskBoxBorderColors.h"
|
||||
#include "QskBoxBorderMetrics.h"
|
||||
#include "QskBoxRenderer.h"
|
||||
#include "QskBoxRendererColorMap.h"
|
||||
#include "QskFunctions.h"
|
||||
#include "QskGradientDirection.h"
|
||||
#include "QskVertex.h"
|
||||
|
||||
using namespace QskVertex;
|
||||
|
||||
namespace
|
||||
{
|
||||
class VRectIterator
|
||||
{
|
||||
public:
|
||||
inline VRectIterator( const Quad& rect )
|
||||
: m_rect( rect )
|
||||
, m_value( rect.top )
|
||||
{
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setGradientLine( const ColorIterator& it, ColoredLine* line )
|
||||
{
|
||||
line->setHLine( m_rect.left, m_rect.right, it.value(), it.color() );
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setContourLine( const ColorIterator& it, ColoredLine* line )
|
||||
{
|
||||
line->setHLine( m_rect.left, m_rect.right, m_value, it.colorAt( m_value ) );
|
||||
}
|
||||
|
||||
inline qreal value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
inline bool advance()
|
||||
{
|
||||
if ( m_value == m_rect.top )
|
||||
{
|
||||
m_value = m_rect.bottom;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
const Quad& m_rect;
|
||||
qreal m_value;
|
||||
};
|
||||
|
||||
class HRectIterator
|
||||
{
|
||||
public:
|
||||
inline HRectIterator( const Quad& rect )
|
||||
: m_rect( rect )
|
||||
, m_value( rect.left )
|
||||
{
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setGradientLine( const ColorIterator& it, ColoredLine* line )
|
||||
{
|
||||
line->setVLine( it.value(), m_rect.top, m_rect.bottom, it.color() );
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setContourLine( const ColorIterator& it, ColoredLine* line )
|
||||
{
|
||||
line->setVLine( m_value, m_rect.top, m_rect.bottom, it.colorAt( m_value ) );
|
||||
}
|
||||
|
||||
inline qreal value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
inline bool advance()
|
||||
{
|
||||
if ( m_value == m_rect.left )
|
||||
{
|
||||
m_value = m_rect.right;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
const Quad& m_rect;
|
||||
qreal m_value;
|
||||
};
|
||||
|
||||
class DSquareIterator
|
||||
{
|
||||
public:
|
||||
inline DSquareIterator( const Quad& rect )
|
||||
: m_rect( rect )
|
||||
, m_step( 0 )
|
||||
{
|
||||
Q_ASSERT( rect.width == rect.height );
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setGradientLine( const ColorIterator& it, ColoredLine* line )
|
||||
{
|
||||
const auto v = it.value();
|
||||
|
||||
if ( v <= 0.5 )
|
||||
{
|
||||
const qreal dt = m_rect.width * 2 * v;
|
||||
|
||||
line->setLine( m_rect.left, m_rect.top + dt,
|
||||
m_rect.left + dt, m_rect.top, it.color() );
|
||||
}
|
||||
else
|
||||
{
|
||||
const qreal dt = m_rect.width * 2 * ( v - 0.5 );
|
||||
line->setLine( m_rect.left + dt, m_rect.bottom,
|
||||
m_rect.right, m_rect.top + dt, it.color() );
|
||||
}
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setContourLine( const ColorIterator& it, ColoredLine* line )
|
||||
{
|
||||
const auto color = it.colorAt( value() );
|
||||
const auto& r = m_rect;
|
||||
|
||||
switch ( m_step )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
line->setLine( r.left, r.top, r.left, r.top, color );
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
line->setLine( r.left, r.bottom, r.right, r.top, color );
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
line->setLine( r.right, r.bottom, r.right, r.bottom, color );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline qreal value() const
|
||||
{
|
||||
return m_step * 0.5;
|
||||
}
|
||||
|
||||
inline bool advance()
|
||||
{
|
||||
return ++m_step <= 2;
|
||||
}
|
||||
|
||||
private:
|
||||
const Quad& m_rect;
|
||||
int m_step;
|
||||
};
|
||||
|
||||
class DRectIterator
|
||||
{
|
||||
public:
|
||||
inline DRectIterator( const Quad& rect )
|
||||
: m_rect( rect )
|
||||
, m_step( 0 )
|
||||
{
|
||||
const qreal w = rect.width;
|
||||
const qreal h = rect.height;
|
||||
|
||||
Q_ASSERT( w != h );
|
||||
|
||||
const qreal w2 = w * w;
|
||||
const qreal h2 = h * h;
|
||||
|
||||
m_fx = ( w2 + h2 ) / w;
|
||||
m_fy = ( w2 + h2 ) / h;
|
||||
|
||||
m_lx = m_rect.top - h2 / w;
|
||||
m_ly = m_rect.left - w2 / h;
|
||||
|
||||
m_valueTR = w2 / ( w2 + h2 );
|
||||
m_valueBL = h2 / ( w2 + h2 );
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setGradientLine( const ColorIterator& it, ColoredLine* line )
|
||||
{
|
||||
const auto v = it.value();
|
||||
const auto color = it.color();
|
||||
const auto& r = m_rect;
|
||||
|
||||
switch ( m_step )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
const qreal dx = v * m_fx;
|
||||
const qreal dy = v * m_fy;
|
||||
|
||||
line->setLine( r.left, r.top + dy, r.left + dx, r.top, color );
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if ( r.width > r.height )
|
||||
{
|
||||
const qreal dx = v * m_fx;
|
||||
line->setLine( m_lx + dx, r.bottom, r.left + dx, r.top, color );
|
||||
}
|
||||
else
|
||||
{
|
||||
const qreal dy = v * m_fy;
|
||||
line->setLine( r.left, r.top + dy, r.right, m_ly + dy, color );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
const qreal dx = v * m_fx;
|
||||
const qreal dy = v * m_fy;
|
||||
|
||||
line->setLine( m_lx + dx, r.bottom, r.right, m_ly + dy, color );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setContourLine( const ColorIterator& it, ColoredLine* line )
|
||||
{
|
||||
const auto& r = m_rect;
|
||||
|
||||
switch ( m_step )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
line->setLine( r.left, r.top,
|
||||
r.left, r.top, it.colorAt( 0.0 ) );
|
||||
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
if ( r.width >= r.height )
|
||||
{
|
||||
const qreal dx = m_valueBL * m_fx;
|
||||
|
||||
line->setLine( r.left, r.bottom,
|
||||
r.left + dx, r.top, it.colorAt( m_valueBL ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
const qreal dy = m_valueTR * m_fy;
|
||||
|
||||
line->setLine( r.left, r.top + dy,
|
||||
r.right, r.top, it.colorAt( m_valueTR ) );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if ( r.width >= r.height )
|
||||
{
|
||||
const qreal dx = m_valueTR * m_fx;
|
||||
|
||||
line->setLine( r.left + dx, r.bottom,
|
||||
r.right, r.top, it.colorAt( m_valueTR ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
const qreal dy = m_valueBL * m_fy;
|
||||
|
||||
line->setLine( r.left, r.bottom,
|
||||
r.right, r.top + dy, it.colorAt( m_valueBL ) );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
line->setLine( r.right, r.bottom,
|
||||
r.right, r.bottom, it.colorAt( 1.0 ) );
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Q_ASSERT( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline qreal value() const
|
||||
{
|
||||
switch ( m_step )
|
||||
{
|
||||
case 0:
|
||||
return 0.0;
|
||||
|
||||
case 1:
|
||||
return std::min( m_valueBL, m_valueTR );
|
||||
|
||||
case 2:
|
||||
return std::max( m_valueBL, m_valueTR );
|
||||
|
||||
default:
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool advance()
|
||||
{
|
||||
return ++m_step <= 3;
|
||||
}
|
||||
|
||||
private:
|
||||
const Quad& m_rect;
|
||||
|
||||
qreal m_fx, m_fy;
|
||||
qreal m_lx, m_ly;
|
||||
qreal m_valueTR, m_valueBL;
|
||||
|
||||
int m_step;
|
||||
};
|
||||
}
|
||||
|
||||
static inline void qskCreateFillOrdered( const Quad& rect,
|
||||
const QskGradient& gradient, ColoredLine* line )
|
||||
{
|
||||
const auto dir = gradient.linearDirection();
|
||||
|
||||
if ( dir.isHorizontal() )
|
||||
{
|
||||
HRectIterator it( rect );
|
||||
line = QskVertex::fillOrdered( it, rect.left, rect.right, gradient, line );
|
||||
}
|
||||
else if ( dir.isVertical() )
|
||||
{
|
||||
VRectIterator it( rect );
|
||||
line = QskVertex::fillOrdered( it, rect.top, rect.bottom, gradient, line );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rect.width == rect.height )
|
||||
{
|
||||
DSquareIterator it( rect );
|
||||
line = QskVertex::fillOrdered( it, 0.0, 1.0, gradient, line );
|
||||
}
|
||||
else
|
||||
{
|
||||
DRectIterator it( rect );
|
||||
line = QskVertex::fillOrdered( it, 0.0, 1.0, gradient, line );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< class ColorMap, class Line >
|
||||
static inline void qskCreateFillRandom( Qt::Orientation orientation,
|
||||
const Quad& r, const ColorMap& map, Line* line )
|
||||
{
|
||||
if ( orientation == Qt::Vertical )
|
||||
{
|
||||
( line++ )->setLine( r.left, r.top, r.right, r.top, map.colorAt( 0.0 ) );
|
||||
( line++ )->setLine( r.left, r.bottom, r.right, r.bottom, map.colorAt( 1.0 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
( line++ )->setLine( r.left, r.top, r.left, r.bottom, map.colorAt( 0.0 ) );
|
||||
( line++ )->setLine( r.right, r.top, r.right, r.bottom, map.colorAt( 1.0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
template< class Line >
|
||||
static inline void qskCreateBorderMonochrome(
|
||||
const Quad& out, const Quad& in, Color color, Line* line )
|
||||
{
|
||||
auto l = line;
|
||||
|
||||
( l++ )->setLine( in.right, in.bottom, out.right, out.bottom, color );
|
||||
( l++ )->setLine( in.left, in.bottom, out.left, out.bottom, color );
|
||||
( l++ )->setLine( in.left, in.top, out.left, out.top, color );
|
||||
( l++ )->setLine( in.right, in.top, out.right, out.top, color );
|
||||
|
||||
*l = line[ 0 ];
|
||||
}
|
||||
|
||||
template< class Line >
|
||||
static inline void qskCreateBorder(
|
||||
const Quad& out, const Quad& in,
|
||||
const QskBoxBorderColors& colors, Line* line )
|
||||
{
|
||||
const qreal dx1 = in.right - in.left;
|
||||
const qreal dx2 = out.right - out.left;
|
||||
const qreal dy1 = in.top - in.bottom;
|
||||
const qreal dy2 = out.top - out.bottom;
|
||||
|
||||
{
|
||||
const auto stops = colors.bottom().stops();
|
||||
|
||||
if ( stops.first().position() > 0.0 )
|
||||
{
|
||||
( line++ )->setLine( in.right, in.bottom,
|
||||
out.right, out.bottom, stops.first().rgb() );
|
||||
}
|
||||
|
||||
for( const auto& stop : stops )
|
||||
{
|
||||
const qreal x1 = in.right - stop.position() * dx1;
|
||||
const qreal x2 = out.right - stop.position() * dx2;
|
||||
|
||||
( line++ )->setLine( x1, in.bottom, x2, out.bottom, stop.rgb() );
|
||||
}
|
||||
|
||||
if ( stops.last().position() < 1.0 )
|
||||
{
|
||||
( line++ )->setLine( in.left, in.bottom,
|
||||
out.left, out.bottom, stops.last().rgb() );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto stops = colors.left().stops();
|
||||
|
||||
if ( stops.first().position() > 0.0 )
|
||||
{
|
||||
( line++ )->setLine( in.left, in.bottom,
|
||||
out.left, out.bottom, stops.first().rgb() );
|
||||
}
|
||||
|
||||
for( const auto& stop : stops )
|
||||
{
|
||||
const qreal y1 = in.bottom + stop.position() * dy1;
|
||||
const qreal y2 = out.bottom + stop.position() * dy2;
|
||||
|
||||
( line++ )->setLine( in.left, y1, out.left, y2, stop.rgb() );
|
||||
}
|
||||
|
||||
if ( stops.last().position() < 1.0 )
|
||||
{
|
||||
( line++ )->setLine( in.left, in.top,
|
||||
out.left, out.top, stops.last().rgb() );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto stops = colors.top().stops();
|
||||
|
||||
if ( stops.first().position() > 0.0 )
|
||||
{
|
||||
( line++ )->setLine( in.left, in.top,
|
||||
out.left, out.top, stops.first().rgb() );
|
||||
}
|
||||
|
||||
for( const auto& stop : stops )
|
||||
{
|
||||
const qreal x1 = in.left + stop.position() * dx1;
|
||||
const qreal x2 = out.left + stop.position() * dx2;
|
||||
|
||||
( line++ )->setLine( x1, in.top, x2, out.top, stop.rgb() );
|
||||
}
|
||||
|
||||
if ( stops.last().position() < 1.0 )
|
||||
{
|
||||
( line++ )->setLine( in.right, in.top,
|
||||
out.right, out.top, stops.last().rgb() );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto stops = colors.right().stops();
|
||||
|
||||
if ( stops.first().position() > 0.0 )
|
||||
{
|
||||
( line++ )->setLine( in.right, in.top,
|
||||
out.right, out.top, stops.first().rgb() );
|
||||
}
|
||||
|
||||
for( const auto& stop : stops )
|
||||
{
|
||||
const qreal y1 = in.bottom + ( 1 - stop.position() ) * dy1;
|
||||
const qreal y2 = out.bottom + ( 1 - stop.position() ) * dy2;
|
||||
|
||||
( line++ )->setLine( in.right, y1, out.right, y2, stop.rgb() );
|
||||
}
|
||||
|
||||
if ( stops.last().position() < 1.0 )
|
||||
{
|
||||
( line++ )->setLine( in.right, in.bottom,
|
||||
out.right, out.bottom, stops.last().rgb() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QskBoxRenderer::renderRectBorder( const QRectF& rect,
|
||||
const QskBoxBorderMetrics& border, QSGGeometry& geometry )
|
||||
{
|
||||
const Quad out = rect;
|
||||
const Quad in = qskValidOrEmptyInnerRect( rect, border.widths() );
|
||||
|
||||
if ( out == in )
|
||||
{
|
||||
allocateLines< Line >( geometry, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
const auto line = allocateLines< Line >( geometry, 4 + 1 );
|
||||
qskCreateBorderMonochrome( out, in, Color(), line );
|
||||
}
|
||||
|
||||
void QskBoxRenderer::renderRectFill( const QRectF& rect,
|
||||
const QskBoxBorderMetrics& border, QSGGeometry& geometry )
|
||||
{
|
||||
const Quad quad = qskValidOrEmptyInnerRect( rect, border.widths() );
|
||||
|
||||
if ( quad.isEmpty() )
|
||||
{
|
||||
geometry.allocate( 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
geometry.allocate( 4 );
|
||||
|
||||
auto p = geometry.vertexDataAsPoint2D();
|
||||
p[0].set( quad.left, quad.top );
|
||||
p[1].set( quad.right, quad.top );
|
||||
p[2].set( quad.left, quad.bottom );
|
||||
p[3].set( quad.right, quad.bottom );
|
||||
}
|
||||
|
||||
void QskBoxRenderer::renderRect( const QRectF& rect,
|
||||
const QskBoxBorderMetrics& border, const QskBoxBorderColors& borderColors,
|
||||
const QskGradient& gradient, QSGGeometry& geometry )
|
||||
{
|
||||
const Quad out = rect;
|
||||
const Quad in = qskValidOrEmptyInnerRect( rect, border.widths() );
|
||||
|
||||
int fillLineCount = 0;
|
||||
if ( gradient.isVisible() && !in.isEmpty() )
|
||||
{
|
||||
fillLineCount = gradient.stepCount() + 1;
|
||||
|
||||
if ( !gradient.isMonochrome() && gradient.linearDirection().isTilted() )
|
||||
{
|
||||
// extra lines for the corners
|
||||
|
||||
fillLineCount++;
|
||||
if ( in.width != in.height )
|
||||
fillLineCount++;
|
||||
}
|
||||
}
|
||||
|
||||
int borderLineCount = 0;
|
||||
if ( in != out )
|
||||
{
|
||||
const auto& bc = borderColors;
|
||||
|
||||
if ( bc.isVisible() )
|
||||
{
|
||||
// We can build a rectangular border from the 4 diagonal
|
||||
// lines at the corners, but need an additional line
|
||||
// for closing the border.
|
||||
|
||||
borderLineCount = 4 + 1;
|
||||
|
||||
if ( !bc.isMonochrome() )
|
||||
{
|
||||
// we might need extra lines to separate colors
|
||||
// at the non closing corners
|
||||
|
||||
// ### As an optimization we could check orientation and colors
|
||||
// to test whether colors are the same
|
||||
const int additionalLines = -1
|
||||
+ bc.left().stepCount()
|
||||
+ bc.top().stepCount()
|
||||
+ bc.right().stepCount()
|
||||
+ bc.bottom().stepCount();
|
||||
|
||||
borderLineCount += qMax( additionalLines, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto line = allocateLines< ColoredLine >( geometry, borderLineCount + fillLineCount );
|
||||
|
||||
if ( fillLineCount > 0 )
|
||||
{
|
||||
if ( gradient.isMonochrome() )
|
||||
{
|
||||
const ColorMapSolid colorMap( gradient );
|
||||
qskCreateFillRandom( Qt::Vertical, in, colorMap, line );
|
||||
}
|
||||
else
|
||||
{
|
||||
bool fillRandom = gradient.stepCount() <= 1;
|
||||
if ( fillRandom )
|
||||
{
|
||||
/*
|
||||
Not necessarily a requirement for being ordered,
|
||||
but we didn't implement a random fill algo for
|
||||
diagonal gradients yet.
|
||||
*/
|
||||
fillRandom = !gradient.linearDirection().isTilted();
|
||||
}
|
||||
|
||||
if ( fillRandom )
|
||||
{
|
||||
const auto orientation = gradient.linearDirection().isVertical()
|
||||
? Qt::Vertical : Qt::Horizontal;
|
||||
|
||||
const ColorMapGradient colorMap( gradient );
|
||||
qskCreateFillRandom( orientation, in, colorMap, line );
|
||||
}
|
||||
else
|
||||
{
|
||||
qskCreateFillOrdered( in, gradient, line );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( borderLineCount > 0 )
|
||||
{
|
||||
const auto& bc = borderColors;
|
||||
auto fillLines = line + fillLineCount;
|
||||
|
||||
if ( bc.isMonochrome() )
|
||||
{
|
||||
const auto rgb = bc.left().rgbStart();
|
||||
qskCreateBorderMonochrome( rect, in, Color( rgb ), fillLines );
|
||||
}
|
||||
else
|
||||
{
|
||||
qskCreateBorder( rect, in, bc, fillLines );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QskBoxRenderer::renderRectFill( const QskVertex::Quad& rect,
|
||||
const QskGradient& gradient, QskVertex::ColoredLine* line )
|
||||
{
|
||||
qskCreateFillOrdered( rect, gradient, line );
|
||||
}
|
551
src/nodes/QskRectRenderer.cpp
Normal file
551
src/nodes/QskRectRenderer.cpp
Normal file
@ -0,0 +1,551 @@
|
||||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskBoxBorderColors.h"
|
||||
#include "QskBoxBorderMetrics.h"
|
||||
#include "QskRectRenderer.h"
|
||||
#include "QskBoxRendererColorMap.h"
|
||||
#include "QskGradient.h"
|
||||
#include "QskGradientDirection.h"
|
||||
#include "QskFunctions.h"
|
||||
#include "QskVertex.h"
|
||||
|
||||
using namespace QskVertex;
|
||||
|
||||
namespace
|
||||
{
|
||||
class HVRectIterator
|
||||
{
|
||||
public:
|
||||
inline HVRectIterator( const Quad& rect, const QLineF& vector )
|
||||
: m_rect( rect )
|
||||
, m_vertical( vector.x1() == vector.x2() )
|
||||
{
|
||||
if ( m_vertical )
|
||||
{
|
||||
m_t = rect.top + vector.y1() * rect.height;
|
||||
m_dt = vector.dy() * rect.height;
|
||||
|
||||
m_values[0] = ( rect.top - m_t ) / m_dt;
|
||||
m_values[1] = ( rect.bottom - m_t ) / m_dt;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_t = rect.left + vector.x1() * rect.width;
|
||||
m_dt = vector.dx() * rect.width;
|
||||
|
||||
m_values[0] = ( rect.left - m_t ) / m_dt;
|
||||
m_values[1] = ( rect.right - m_t ) / m_dt;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool setGradientLine( qreal value, Color color, ColoredLine* line )
|
||||
{
|
||||
if ( value <= m_values[0] || value >= m_values[1] )
|
||||
return false;
|
||||
|
||||
const auto v = m_t + value * m_dt;
|
||||
|
||||
if ( m_vertical )
|
||||
line->setHLine( m_rect.left, m_rect.right, v, color );
|
||||
else
|
||||
line->setVLine( v, m_rect.top, m_rect.bottom, color );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void setContourLine( Color color, ColoredLine* line )
|
||||
{
|
||||
if ( m_vertical )
|
||||
{
|
||||
const auto y = m_step ? m_rect.bottom : m_rect.top;
|
||||
line->setLine( m_rect.left, y, m_rect.right, y, color );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto x = m_step ? m_rect.right : m_rect.left;
|
||||
line->setLine( x, m_rect.top, x, m_rect.bottom, color );
|
||||
}
|
||||
}
|
||||
|
||||
inline qreal value() const { return m_values[ m_step ? 1 : 0 ]; }
|
||||
inline bool advance() { return m_step++ == 0; }
|
||||
|
||||
private:
|
||||
const Quad& m_rect;
|
||||
qreal m_t, m_dt;
|
||||
qreal m_values[2];
|
||||
const bool m_vertical;
|
||||
int m_step = 0;
|
||||
};
|
||||
|
||||
class DRectIterator
|
||||
{
|
||||
public:
|
||||
inline DRectIterator( const Quad& quad, const QLineF& vector )
|
||||
{
|
||||
m_v.x = quad.left + vector.x1() * quad.width;
|
||||
m_v.y = quad.top + vector.y1() * quad.height;
|
||||
m_v.dx = vector.dx() * quad.width;
|
||||
m_v.dy = vector.dy() * quad.height;
|
||||
|
||||
/*
|
||||
We calculate the values at the corners and order them
|
||||
in increasing order
|
||||
*/
|
||||
|
||||
const qreal lx = ( quad.left - m_v.x ) * m_v.dx;
|
||||
const qreal rx = ( quad.right - m_v.x ) * m_v.dx;
|
||||
const qreal ty = ( quad.top - m_v.y ) * m_v.dy;
|
||||
const qreal by = ( quad.bottom - m_v.y ) * m_v.dy;
|
||||
|
||||
const qreal dot = m_v.dx * m_v.dx + m_v.dy * m_v.dy;
|
||||
|
||||
const qreal tl = ( lx + ty ) / dot;
|
||||
const qreal tr = ( rx + ty ) / dot;
|
||||
const qreal bl = ( lx + by ) / dot;
|
||||
const qreal br = ( rx + by ) / dot;
|
||||
|
||||
if ( ( m_v.dy >= 0.0 ) == ( m_v.dx >= 0.0 ) )
|
||||
{
|
||||
m_corners[0] = { { quad.left, quad.top }, tl };
|
||||
m_corners[1] = { { quad.right, quad.top }, tr };
|
||||
m_corners[2] = { { quad.left, quad.bottom }, bl };
|
||||
m_corners[3] = { { quad.right, quad.bottom }, br };
|
||||
}
|
||||
else
|
||||
{
|
||||
m_corners[0] = { { quad.left, quad.bottom }, bl };
|
||||
m_corners[1] = { { quad.right, quad.bottom }, br };
|
||||
m_corners[2] = { { quad.left, quad.top }, tl };
|
||||
m_corners[3] = { { quad.right, quad.top }, tr };
|
||||
}
|
||||
|
||||
if ( m_corners[0].value > m_corners[3].value )
|
||||
qSwap( m_corners[0], m_corners[3] );
|
||||
|
||||
if ( m_corners[1].value > m_corners[2].value )
|
||||
qSwap( m_corners[1], m_corners[2] );
|
||||
}
|
||||
|
||||
inline bool setGradientLine( qreal value, Color color, ColoredLine* line )
|
||||
{
|
||||
if ( value <= m_corners[0].value || value >= m_corners[3].value )
|
||||
return false;
|
||||
|
||||
const qreal m = m_v.dy / m_v.dx;
|
||||
|
||||
const qreal x = m_v.x + m_v.dx * value;
|
||||
const qreal y = m_v.y + m_v.dy * value;
|
||||
|
||||
const bool on = m_corners[0].pos.x() == m_corners[1].pos.x();
|
||||
|
||||
QPointF p1, p2;
|
||||
|
||||
switch( m_step )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
p1 = p2 = m_corners[0].pos;
|
||||
|
||||
if ( on )
|
||||
{
|
||||
p1.ry() = y + ( x - p1.x() ) / m;
|
||||
p2.rx() = x + ( y - p2.y() ) * m;
|
||||
}
|
||||
else
|
||||
{
|
||||
p1.rx() = x + ( y - p1.y() ) * m;
|
||||
p2.ry() = y + ( x - p2.x() ) / m;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
p1 = m_corners[1].pos;
|
||||
p2 = m_corners[0].pos;
|
||||
|
||||
if ( on )
|
||||
{
|
||||
p1.rx() = x + ( y - p1.y() ) * m;
|
||||
p2.rx() = x + ( y - p2.y() ) * m;
|
||||
}
|
||||
else
|
||||
{
|
||||
p1.ry() = y + ( x - p1.x() ) / m;
|
||||
p2.ry() = y + ( x - p2.x() ) / m;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
p1 = m_corners[1].pos;
|
||||
p2 = m_corners[2].pos;
|
||||
|
||||
if ( on )
|
||||
{
|
||||
p1.rx() = x + ( y - p1.y() ) * m;
|
||||
p2.ry() = y + ( x - p2.x() ) / m;
|
||||
}
|
||||
else
|
||||
{
|
||||
p1.ry() = y + ( x - p1.x() ) / m;
|
||||
p2.rx() = x + ( y - p2.y() ) * m;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( p1.x() < p2.x() )
|
||||
line->setLine( p1.x(), p1.y(), p2.x(), p2.y(), color );
|
||||
else
|
||||
line->setLine( p2.x(), p2.y(), p1.x(), p1.y(), color );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void setContourLine( Color color, ColoredLine* line )
|
||||
{
|
||||
if( m_step == 0 || m_step == 3 )
|
||||
{
|
||||
const auto& p = m_corners[m_step].pos;
|
||||
line->setLine( p.x(), p.y(), p.x(), p.y(), color );
|
||||
}
|
||||
else
|
||||
{
|
||||
const qreal m = m_v.dy / m_v.dx;
|
||||
|
||||
auto p1 = m_corners[m_step - 1].pos;
|
||||
const auto& p2 = m_corners[m_step].pos;
|
||||
|
||||
if ( p1.x() == m_corners[m_step + 1].pos.x() )
|
||||
p1.ry() = p2.y() + ( p2.x() - p1.x() ) / m;
|
||||
else
|
||||
p1.rx() = p2.x() + ( p2.y() - p1.y() ) * m;
|
||||
|
||||
if ( p1.x() <= p2.x() )
|
||||
line->setLine( p1.x(), p1.y(), p2.x(), p2.y(), color );
|
||||
else
|
||||
line->setLine( p2.x(), p2.y(), p1.x(), p1.y(), color );
|
||||
}
|
||||
}
|
||||
|
||||
inline qreal value() const
|
||||
{
|
||||
return m_corners[ m_step ].value;
|
||||
}
|
||||
|
||||
inline bool advance()
|
||||
{
|
||||
return ++m_step <= 3;
|
||||
}
|
||||
|
||||
private:
|
||||
struct { qreal x, y, dx, dy; } m_v;
|
||||
struct { QPointF pos; qreal value; } m_corners[4];
|
||||
|
||||
int m_step = 0;
|
||||
};
|
||||
}
|
||||
|
||||
static ColoredLine* qskAddFillLines( const Quad& rect,
|
||||
const QskGradient& gradient, ColoredLine* line )
|
||||
{
|
||||
const auto dir = gradient.linearDirection();
|
||||
|
||||
if ( dir.isTilted() )
|
||||
{
|
||||
DRectIterator it( rect, dir.vector() );
|
||||
line = QskVertex::fillOrdered( it, gradient, line );
|
||||
}
|
||||
else
|
||||
{
|
||||
HVRectIterator it( rect, dir.vector() );
|
||||
line = QskVertex::fillOrdered( it, gradient, line );
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
template< class Line >
|
||||
static inline Line* qskAddBorderLines(
|
||||
const Quad& out, const Quad& in, Color color, Line* line )
|
||||
{
|
||||
line[0].setLine( in.right, in.bottom, out.right, out.bottom, color );
|
||||
line[1].setLine( in.left, in.bottom, out.left, out.bottom, color );
|
||||
line[2].setLine( in.left, in.top, out.left, out.top, color );
|
||||
line[3].setLine( in.right, in.top, out.right, out.top, color );
|
||||
line[4] = line[ 0 ];
|
||||
|
||||
return line + 5;
|
||||
}
|
||||
|
||||
template< class Line >
|
||||
static inline Line* qskAddBorderLines(
|
||||
const Quad& out, const Quad& in,
|
||||
const QskBoxBorderColors& colors, Line* line )
|
||||
{
|
||||
const qreal dx1 = in.right - in.left;
|
||||
const qreal dx2 = out.right - out.left;
|
||||
const qreal dy1 = in.top - in.bottom;
|
||||
const qreal dy2 = out.top - out.bottom;
|
||||
|
||||
{
|
||||
const auto stops = colors.bottom().stops();
|
||||
|
||||
if ( stops.first().position() > 0.0 )
|
||||
{
|
||||
( line++ )->setLine( in.right, in.bottom,
|
||||
out.right, out.bottom, stops.first().rgb() );
|
||||
}
|
||||
|
||||
for( const auto& stop : stops )
|
||||
{
|
||||
const qreal x1 = in.right - stop.position() * dx1;
|
||||
const qreal x2 = out.right - stop.position() * dx2;
|
||||
|
||||
( line++ )->setLine( x1, in.bottom, x2, out.bottom, stop.rgb() );
|
||||
}
|
||||
|
||||
if ( stops.last().position() < 1.0 )
|
||||
{
|
||||
( line++ )->setLine( in.left, in.bottom,
|
||||
out.left, out.bottom, stops.last().rgb() );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto stops = colors.left().stops();
|
||||
|
||||
if ( stops.first().position() > 0.0 )
|
||||
{
|
||||
( line++ )->setLine( in.left, in.bottom,
|
||||
out.left, out.bottom, stops.first().rgb() );
|
||||
}
|
||||
|
||||
for( const auto& stop : stops )
|
||||
{
|
||||
const qreal y1 = in.bottom + stop.position() * dy1;
|
||||
const qreal y2 = out.bottom + stop.position() * dy2;
|
||||
|
||||
( line++ )->setLine( in.left, y1, out.left, y2, stop.rgb() );
|
||||
}
|
||||
|
||||
if ( stops.last().position() < 1.0 )
|
||||
{
|
||||
( line++ )->setLine( in.left, in.top,
|
||||
out.left, out.top, stops.last().rgb() );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto stops = colors.top().stops();
|
||||
|
||||
if ( stops.first().position() > 0.0 )
|
||||
{
|
||||
( line++ )->setLine( in.left, in.top,
|
||||
out.left, out.top, stops.first().rgb() );
|
||||
}
|
||||
|
||||
for( const auto& stop : stops )
|
||||
{
|
||||
const qreal x1 = in.left + stop.position() * dx1;
|
||||
const qreal x2 = out.left + stop.position() * dx2;
|
||||
|
||||
( line++ )->setLine( x1, in.top, x2, out.top, stop.rgb() );
|
||||
}
|
||||
|
||||
if ( stops.last().position() < 1.0 )
|
||||
{
|
||||
( line++ )->setLine( in.right, in.top,
|
||||
out.right, out.top, stops.last().rgb() );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto stops = colors.right().stops();
|
||||
|
||||
if ( stops.first().position() > 0.0 )
|
||||
{
|
||||
( line++ )->setLine( in.right, in.top,
|
||||
out.right, out.top, stops.first().rgb() );
|
||||
}
|
||||
|
||||
for( const auto& stop : stops )
|
||||
{
|
||||
const qreal y1 = in.bottom + ( 1 - stop.position() ) * dy1;
|
||||
const qreal y2 = out.bottom + ( 1 - stop.position() ) * dy2;
|
||||
|
||||
( line++ )->setLine( in.right, y1, out.right, y2, stop.rgb() );
|
||||
}
|
||||
|
||||
if ( stops.last().position() < 1.0 )
|
||||
{
|
||||
( line++ )->setLine( in.right, in.bottom,
|
||||
out.right, out.bottom, stops.last().rgb() );
|
||||
}
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
void QskRectRenderer::renderBorder( const QRectF& rect,
|
||||
const QskBoxBorderMetrics& border, QSGGeometry& geometry )
|
||||
{
|
||||
const Quad out = rect;
|
||||
const Quad in = qskValidOrEmptyInnerRect( rect, border.widths() );
|
||||
|
||||
if ( out == in )
|
||||
{
|
||||
allocateLines< Line >( geometry, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
const auto line = allocateLines< Line >( geometry, 4 + 1 );
|
||||
qskAddBorderLines( out, in, Color(), line );
|
||||
}
|
||||
|
||||
void QskRectRenderer::renderFill0( const QskVertex::Quad& rect,
|
||||
const QskGradient& gradient, QskVertex::ColoredLine* line )
|
||||
{
|
||||
qskAddFillLines( rect, gradient, line );
|
||||
}
|
||||
|
||||
void QskRectRenderer::renderFill( const QRectF& rect,
|
||||
const QskBoxBorderMetrics& border, QSGGeometry& geometry )
|
||||
{
|
||||
const Quad quad = qskValidOrEmptyInnerRect( rect, border.widths() );
|
||||
|
||||
if ( quad.isEmpty() )
|
||||
{
|
||||
geometry.allocate( 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
geometry.allocate( 4 );
|
||||
|
||||
auto p = geometry.vertexDataAsPoint2D();
|
||||
p[0].set( quad.left, quad.top );
|
||||
p[1].set( quad.right, quad.top );
|
||||
p[2].set( quad.left, quad.bottom );
|
||||
p[3].set( quad.right, quad.bottom );
|
||||
}
|
||||
|
||||
void QskRectRenderer::renderRect( const QRectF& rect,
|
||||
const QskBoxBorderMetrics& border, const QskBoxBorderColors& borderColors,
|
||||
const QskGradient& gradient, QSGGeometry& geometry )
|
||||
{
|
||||
const Quad out = rect;
|
||||
const Quad in = qskValidOrEmptyInnerRect( rect, border.widths() );
|
||||
|
||||
int fillLineCount = 0;
|
||||
if ( gradient.isVisible() && !in.isEmpty() )
|
||||
{
|
||||
fillLineCount = gradient.stepCount() + 1;
|
||||
|
||||
if ( !gradient.isMonochrome() && gradient.linearDirection().isTilted() )
|
||||
fillLineCount += 2; // contour lines for the corners
|
||||
}
|
||||
|
||||
int borderLineCount = 0;
|
||||
if ( in != out && borderColors.isVisible() )
|
||||
{
|
||||
// We can build a rectangular border from the 4 diagonal
|
||||
// lines at the corners, but need an additional line
|
||||
// for closing the border.
|
||||
|
||||
borderLineCount = 4 + 1;
|
||||
|
||||
if ( !borderColors.isMonochrome() )
|
||||
{
|
||||
// we might need extra lines to separate colors
|
||||
// at the non closing corners
|
||||
|
||||
// ### As an optimization we could check orientation and colors
|
||||
// to test whether colors are the same
|
||||
const int additionalLines = -1
|
||||
+ borderColors.left().stepCount()
|
||||
+ borderColors.top().stepCount()
|
||||
+ borderColors.right().stepCount()
|
||||
+ borderColors.bottom().stepCount();
|
||||
|
||||
borderLineCount += qMax( additionalLines, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
const auto line = allocateLines< ColoredLine >(
|
||||
geometry, borderLineCount + fillLineCount );
|
||||
|
||||
auto l = line;
|
||||
|
||||
if ( fillLineCount > 0 )
|
||||
{
|
||||
if ( gradient.isMonochrome() )
|
||||
{
|
||||
const auto c = gradient.rgbStart();
|
||||
|
||||
( l++ )->setHLine( rect.left(), rect.right(), rect.top(), c );
|
||||
( l++ )->setHLine( rect.left(), rect.right(), rect.bottom(), c );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( gradient.stepCount() <= 1 && !gradient.linearDirection().isTilted() )
|
||||
{
|
||||
const auto c1 = gradient.rgbStart();
|
||||
const auto c2 = gradient.rgbEnd();
|
||||
|
||||
if ( gradient.linearDirection().isVertical() )
|
||||
{
|
||||
( l++ )->setHLine( rect.left(), rect.right(), rect.top(), c1 );
|
||||
( l++ )->setHLine( rect.left(), rect.right(), rect.bottom(), c2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
( l++ )->setVLine( rect.left(), rect.top(), rect.bottom(), c1 );
|
||||
( l++ )->setVLine( rect.right(), rect.top(), rect.bottom(), c2 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
l = qskAddFillLines( in, gradient, l );
|
||||
}
|
||||
}
|
||||
|
||||
if ( l < line + fillLineCount )
|
||||
{
|
||||
/*
|
||||
When the the vector exceeds [ 0.0, 1.0 ] we might have
|
||||
gradient lines lying outside the rectangle.
|
||||
Precalculating this effect would save some memory - however
|
||||
these corner cases are not worth to make the implementation
|
||||
even more complicated.
|
||||
So let's fill the memory with duplicates of the final
|
||||
contour line instead.
|
||||
*/
|
||||
const auto& llast = *( l - 1 );
|
||||
while ( l < line + fillLineCount )
|
||||
*l++ = llast;
|
||||
}
|
||||
|
||||
Q_ASSERT( l - line == fillLineCount );
|
||||
}
|
||||
|
||||
if ( borderLineCount > 0 )
|
||||
{
|
||||
if ( borderColors.isMonochrome() )
|
||||
{
|
||||
const auto rgb = borderColors.left().rgbStart();
|
||||
l = qskAddBorderLines( rect, in, Color( rgb ), l );
|
||||
}
|
||||
else
|
||||
{
|
||||
l = qskAddBorderLines( rect, in, borderColors, l );
|
||||
}
|
||||
|
||||
Q_ASSERT( l - line == borderLineCount + fillLineCount );
|
||||
}
|
||||
}
|
47
src/nodes/QskRectRenderer.h
Normal file
47
src/nodes/QskRectRenderer.h
Normal file
@ -0,0 +1,47 @@
|
||||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_RECT_RENDERER_H
|
||||
#define QSK_RECT_RENDERER_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
|
||||
class QskBoxBorderMetrics;
|
||||
class QskBoxBorderColors;
|
||||
class QskGradient;
|
||||
|
||||
class QSGGeometry;
|
||||
class QRectF;
|
||||
|
||||
namespace QskRectRenderer
|
||||
{
|
||||
void renderBorder( const QRectF&,
|
||||
const QskBoxBorderMetrics&, QSGGeometry& );
|
||||
|
||||
void renderFill( const QRectF&,
|
||||
const QskBoxBorderMetrics&, QSGGeometry& );
|
||||
|
||||
void renderRect( const QRectF&, const QskBoxBorderMetrics&,
|
||||
const QskBoxBorderColors&, const QskGradient&, QSGGeometry& );
|
||||
}
|
||||
|
||||
#if 1
|
||||
|
||||
// maybe to QskVertex.h ???
|
||||
namespace QskVertex
|
||||
{
|
||||
class Quad;
|
||||
class ColoredLine;
|
||||
}
|
||||
|
||||
namespace QskRectRenderer
|
||||
{
|
||||
void renderFill0( const QskVertex::Quad&,
|
||||
const QskGradient&, QskVertex::ColoredLine* );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -3,13 +3,14 @@
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskBoxRenderer.h"
|
||||
#include "QskRoundedRectRenderer.h"
|
||||
|
||||
#include "QskBoxBorderColors.h"
|
||||
#include "QskBoxBorderMetrics.h"
|
||||
#include "QskBoxRendererColorMap.h"
|
||||
#include "QskBoxShapeMetrics.h"
|
||||
#include "QskGradientDirection.h"
|
||||
#include "QskRectRenderer.h"
|
||||
|
||||
#include <qmath.h>
|
||||
#include <qsggeometry.h>
|
||||
@ -109,7 +110,7 @@ namespace
|
||||
class BorderValuesUniform
|
||||
{
|
||||
public:
|
||||
inline BorderValuesUniform( const QskBoxRenderer::Metrics& metrics )
|
||||
inline BorderValuesUniform( const QskRoundedRectRenderer::Metrics& metrics )
|
||||
: m_corner( metrics.corner[ 0 ] )
|
||||
, m_dx1( m_corner.radiusInnerX )
|
||||
, m_dy1( m_corner.radiusInnerY )
|
||||
@ -134,14 +135,14 @@ namespace
|
||||
inline qreal dy2( int ) const { return m_dy2; }
|
||||
|
||||
private:
|
||||
const QskBoxRenderer::Metrics::Corner& m_corner;
|
||||
const QskRoundedRectRenderer::Metrics::Corner& m_corner;
|
||||
qreal m_dx1, m_dy1, m_dx2, m_dy2;
|
||||
};
|
||||
|
||||
class BorderValuesNonUniform
|
||||
class BorderValuesMulti
|
||||
{
|
||||
public:
|
||||
inline BorderValuesNonUniform( const QskBoxRenderer::Metrics& metrics )
|
||||
inline BorderValuesMulti( const QskRoundedRectRenderer::Metrics& metrics )
|
||||
: m_uniform( metrics.isRadiusRegular )
|
||||
{
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
@ -225,7 +226,7 @@ namespace
|
||||
class FillValues
|
||||
{
|
||||
public:
|
||||
inline FillValues( const QskBoxRenderer::Metrics& metrics )
|
||||
inline FillValues( const QskRoundedRectRenderer::Metrics& metrics )
|
||||
{
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
@ -290,7 +291,7 @@ namespace
|
||||
class VRectEllipseIterator
|
||||
{
|
||||
public:
|
||||
VRectEllipseIterator( const QskBoxRenderer::Metrics& metrics )
|
||||
VRectEllipseIterator( const QskRoundedRectRenderer::Metrics& metrics )
|
||||
: m_metrics( metrics )
|
||||
, m_values( metrics )
|
||||
{
|
||||
@ -308,27 +309,29 @@ namespace
|
||||
m_arcIterator.reset( c[ m_leadingCorner ].stepCount, false );
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setGradientLine( const ColorIterator& it, ColoredLine* line )
|
||||
inline bool setGradientLine( qreal value, Color color, ColoredLine* line )
|
||||
{
|
||||
const qreal y = it.value();
|
||||
const auto& q = m_metrics.innerQuad;
|
||||
const qreal y = q.top + value * q.height;
|
||||
|
||||
const qreal f = ( y - m_v[ 0 ].y ) / ( m_v[ 1 ].y - m_v[ 0 ].y );
|
||||
const qreal left = m_v[ 0 ].left + f * ( m_v[ 1 ].left - m_v[ 0 ].left );
|
||||
const qreal right = m_v[ 0 ].right + f * ( m_v[ 1 ].right - m_v[ 0 ].right );
|
||||
|
||||
line->setLine( left, y, right, y, it.color() );
|
||||
line->setLine( left, y, right, y, color );
|
||||
return true;
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setContourLine( const ColorIterator& it, ColoredLine* line )
|
||||
inline void setContourLine( Color color, ColoredLine* line )
|
||||
{
|
||||
line->setLine( m_v[ 1 ].left, m_v[ 1 ].y,
|
||||
m_v[ 1 ].right, m_v[ 1 ].y, it.colorAt( m_v[ 1 ].y ) );
|
||||
m_v[ 1 ].right, m_v[ 1 ].y, color );
|
||||
}
|
||||
|
||||
inline qreal value() const
|
||||
{
|
||||
return m_v[ 1 ].y;
|
||||
const auto& q = m_metrics.innerQuad;
|
||||
return ( m_v[ 1 ].y - q.top ) / q.height;
|
||||
}
|
||||
|
||||
inline bool advance()
|
||||
@ -380,7 +383,7 @@ namespace
|
||||
}
|
||||
|
||||
private:
|
||||
const QskBoxRenderer::Metrics& m_metrics;
|
||||
const QskRoundedRectRenderer::Metrics& m_metrics;
|
||||
ArcIterator m_arcIterator;
|
||||
int m_leadingCorner;
|
||||
FillValues m_values;
|
||||
@ -390,7 +393,7 @@ namespace
|
||||
class HRectEllipseIterator
|
||||
{
|
||||
public:
|
||||
HRectEllipseIterator( const QskBoxRenderer::Metrics& metrics )
|
||||
HRectEllipseIterator( const QskRoundedRectRenderer::Metrics& metrics )
|
||||
: m_metrics( metrics )
|
||||
, m_values( metrics )
|
||||
{
|
||||
@ -408,27 +411,29 @@ namespace
|
||||
m_arcIterator.reset( c[ m_leadingCorner ].stepCount, true );
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setGradientLine( const ColorIterator& it, ColoredLine* line )
|
||||
inline bool setGradientLine( qreal value, Color color, ColoredLine* line )
|
||||
{
|
||||
const qreal x = it.value();
|
||||
const auto& q = m_metrics.innerQuad;
|
||||
const qreal x = q.left + value * q.width;
|
||||
|
||||
const qreal f = ( x - m_v[ 0 ].x ) / ( m_v[ 1 ].x - m_v[ 0 ].x );
|
||||
const qreal top = m_v[ 0 ].top + f * ( m_v[ 1 ].top - m_v[ 0 ].top );
|
||||
const qreal bottom = m_v[ 0 ].bottom + f * ( m_v[ 1 ].bottom - m_v[ 0 ].bottom );
|
||||
|
||||
line->setLine( x, top, x, bottom, it.color() );
|
||||
line->setLine( x, top, x, bottom, color );
|
||||
return true;
|
||||
}
|
||||
|
||||
template< class ColorIterator >
|
||||
inline void setContourLine( const ColorIterator& it, ColoredLine* line )
|
||||
inline void setContourLine( Color color, ColoredLine* line )
|
||||
{
|
||||
line->setLine( m_v[ 1 ].x, m_v[ 1 ].top,
|
||||
m_v[ 1 ].x, m_v[ 1 ].bottom, it.colorAt( m_v[ 1 ].x ) );
|
||||
m_v[ 1 ].x, m_v[ 1 ].bottom, color );
|
||||
}
|
||||
|
||||
inline qreal value() const
|
||||
{
|
||||
return m_v[ 1 ].x;
|
||||
const auto& q = m_metrics.innerQuad;
|
||||
return ( m_v[ 1 ].x - q.left ) / q.width;
|
||||
}
|
||||
|
||||
inline bool advance()
|
||||
@ -479,7 +484,7 @@ namespace
|
||||
}
|
||||
|
||||
private:
|
||||
const QskBoxRenderer::Metrics& m_metrics;
|
||||
const QskRoundedRectRenderer::Metrics& m_metrics;
|
||||
ArcIterator m_arcIterator;
|
||||
int m_leadingCorner;
|
||||
FillValues m_values;
|
||||
@ -513,7 +518,8 @@ namespace
|
||||
class BorderMapGradient
|
||||
{
|
||||
public:
|
||||
inline BorderMapGradient( int stepCount, const QskGradient& gradient1, const QskGradient& gradient2 )
|
||||
inline BorderMapGradient( int stepCount,
|
||||
const QskGradient& gradient1, const QskGradient& gradient2 )
|
||||
: m_stepCount( stepCount )
|
||||
, m_color1( gradient1.rgbStart() )
|
||||
, m_color2( gradient2.rgbEnd() )
|
||||
@ -541,7 +547,7 @@ namespace
|
||||
class Stroker
|
||||
{
|
||||
public:
|
||||
inline Stroker( const QskBoxRenderer::Metrics& metrics )
|
||||
inline Stroker( const QskRoundedRectRenderer::Metrics& metrics )
|
||||
: m_metrics( metrics )
|
||||
{
|
||||
}
|
||||
@ -864,7 +870,7 @@ namespace
|
||||
}
|
||||
|
||||
private:
|
||||
const QskBoxRenderer::Metrics& m_metrics;
|
||||
const QskRoundedRectRenderer::Metrics& m_metrics;
|
||||
};
|
||||
}
|
||||
|
||||
@ -874,7 +880,7 @@ static inline Qt::Orientation qskQtOrientation( const QskGradient& gradient )
|
||||
}
|
||||
|
||||
static inline int qskFillLineCount(
|
||||
const QskBoxRenderer::Metrics& metrics, const QskGradient& gradient )
|
||||
const QskRoundedRectRenderer::Metrics& metrics, const QskGradient& gradient )
|
||||
{
|
||||
const int stepCount = metrics.corner[ 0 ].stepCount;
|
||||
|
||||
@ -947,7 +953,7 @@ static inline int qskFillLineCount(
|
||||
|
||||
template< class Line, class BorderMap, class FillMap >
|
||||
static inline void qskRenderLines(
|
||||
const QskBoxRenderer::Metrics& metrics,
|
||||
const QskRoundedRectRenderer::Metrics& metrics,
|
||||
Qt::Orientation orientation, Line* borderLines,
|
||||
const BorderMap& borderMapTL, const BorderMap& borderMapTR,
|
||||
const BorderMap& borderMapBL, const BorderMap& borderMapBR,
|
||||
@ -964,7 +970,7 @@ static inline void qskRenderLines(
|
||||
}
|
||||
else
|
||||
{
|
||||
Stroker< Line, BorderValuesNonUniform > stroker( metrics );
|
||||
Stroker< Line, BorderValuesMulti > stroker( metrics );
|
||||
stroker.createLines( orientation, borderLines,
|
||||
borderMapTL, borderMapTR, borderMapBL, borderMapBR,
|
||||
fillLines, fillMap );
|
||||
@ -973,7 +979,7 @@ static inline void qskRenderLines(
|
||||
|
||||
template< class Line, class BorderMap, class FillMap >
|
||||
static inline void qskRenderLines(
|
||||
const QskBoxRenderer::Metrics& metrics, Qt::Orientation orientation,
|
||||
const QskRoundedRectRenderer::Metrics& metrics, Qt::Orientation orientation,
|
||||
Line* borderLines, const BorderMap& borderMap, Line* fillLines,
|
||||
const FillMap& fillMap )
|
||||
{
|
||||
@ -983,7 +989,7 @@ static inline void qskRenderLines(
|
||||
|
||||
template< class Line, class BorderMap >
|
||||
static inline void qskRenderBorderLines(
|
||||
const QskBoxRenderer::Metrics& metrics,
|
||||
const QskRoundedRectRenderer::Metrics& metrics,
|
||||
Qt::Orientation orientation, Line* lines,
|
||||
const BorderMap& borderMapTL, const BorderMap& borderMapTR,
|
||||
const BorderMap& borderMapBL, const BorderMap& borderMapBR )
|
||||
@ -994,7 +1000,7 @@ static inline void qskRenderBorderLines(
|
||||
|
||||
template< class Line, class BorderMap >
|
||||
static inline void qskRenderBorderLines(
|
||||
const QskBoxRenderer::Metrics& metrics,
|
||||
const QskRoundedRectRenderer::Metrics& metrics,
|
||||
Qt::Orientation orientation, Line* lines, const BorderMap& borderMap )
|
||||
{
|
||||
qskRenderBorderLines( metrics, orientation, lines,
|
||||
@ -1002,14 +1008,14 @@ static inline void qskRenderBorderLines(
|
||||
}
|
||||
|
||||
template< class Line, class FillMap >
|
||||
static inline void qskRenderFillLines( const QskBoxRenderer::Metrics& metrics,
|
||||
static inline void qskRenderFillLines( const QskRoundedRectRenderer::Metrics& metrics,
|
||||
Qt::Orientation orientation, Line* lines, const FillMap& fillMap )
|
||||
{
|
||||
qskRenderLines( metrics, orientation,
|
||||
static_cast< Line* >( nullptr ), BorderMapNone(), lines, fillMap );
|
||||
}
|
||||
|
||||
static inline void qskRenderBorder( const QskBoxRenderer::Metrics& metrics,
|
||||
static inline void qskRenderBorder( const QskRoundedRectRenderer::Metrics& metrics,
|
||||
Qt::Orientation orientation, const QskBoxBorderColors& colors, ColoredLine* line )
|
||||
{
|
||||
if ( colors.isMonochrome() )
|
||||
@ -1030,7 +1036,7 @@ static inline void qskRenderBorder( const QskBoxRenderer::Metrics& metrics,
|
||||
}
|
||||
|
||||
static inline void qskRenderFillRandom(
|
||||
const QskBoxRenderer::Metrics& metrics,
|
||||
const QskRoundedRectRenderer::Metrics& metrics,
|
||||
const QskGradient& gradient, ColoredLine* line )
|
||||
{
|
||||
// here we know that: gradient.stepCount() <= 1 !
|
||||
@ -1050,7 +1056,7 @@ static inline void qskRenderFillRandom(
|
||||
}
|
||||
|
||||
static inline void qskRenderBoxRandom(
|
||||
const QskBoxRenderer::Metrics& metrics, const QskBoxBorderColors& borderColors,
|
||||
const QskRoundedRectRenderer::Metrics& metrics, const QskBoxBorderColors& borderColors,
|
||||
const QskGradient& gradient, ColoredLine* fillLine, ColoredLine* borderLine )
|
||||
{
|
||||
// here we know that: gradient.stepCount() <= 1 !
|
||||
@ -1104,11 +1110,9 @@ static inline void qskRenderBoxRandom(
|
||||
}
|
||||
|
||||
static inline void qskRenderFillOrdered(
|
||||
const QskBoxRenderer::Metrics& metrics,
|
||||
const QskRoundedRectRenderer::Metrics& metrics,
|
||||
const QskGradient& gradient, ColoredLine* lines )
|
||||
{
|
||||
const auto& r = metrics.innerQuad;
|
||||
|
||||
/*
|
||||
The algo for irregular radii at opposite corners is not yet
|
||||
implemented TODO ...
|
||||
@ -1117,16 +1121,16 @@ static inline void qskRenderFillOrdered(
|
||||
if ( gradient.linearDirection().isHorizontal() )
|
||||
{
|
||||
HRectEllipseIterator it( metrics );
|
||||
QskVertex::fillOrdered( it, r.left, r.right, gradient, lines );
|
||||
QskVertex::fillOrdered( it, gradient, lines );
|
||||
}
|
||||
else
|
||||
{
|
||||
VRectEllipseIterator it( metrics );
|
||||
QskVertex::fillOrdered( it, r.top, r.bottom, gradient, lines );
|
||||
QskVertex::fillOrdered( it, gradient, lines );
|
||||
}
|
||||
}
|
||||
|
||||
QskBoxRenderer::Metrics::Metrics( const QRectF& rect,
|
||||
QskRoundedRectRenderer::Metrics::Metrics( const QRectF& rect,
|
||||
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border )
|
||||
: outerQuad( rect )
|
||||
{
|
||||
@ -1274,7 +1278,7 @@ QskBoxRenderer::Metrics::Metrics( const QRectF& rect,
|
||||
( borderRight == borderBottom );
|
||||
}
|
||||
|
||||
void QskBoxRenderer::renderRectellipseBorder(
|
||||
void QskRoundedRectRenderer::renderRectellipseBorder(
|
||||
const QRectF& rect, const QskBoxShapeMetrics& shape,
|
||||
const QskBoxBorderMetrics& border, QSGGeometry& geometry )
|
||||
{
|
||||
@ -1293,7 +1297,7 @@ void QskBoxRenderer::renderRectellipseBorder(
|
||||
qskRenderBorderLines( metrics, Qt::Vertical, line, BorderMapNone() );
|
||||
}
|
||||
|
||||
void QskBoxRenderer::renderRectellipseFill(
|
||||
void QskRoundedRectRenderer::renderRectellipseFill(
|
||||
const QRectF& rect, const QskBoxShapeMetrics& shape,
|
||||
const QskBoxBorderMetrics& border, QSGGeometry& geometry )
|
||||
{
|
||||
@ -1349,7 +1353,7 @@ void QskBoxRenderer::renderRectellipseFill(
|
||||
|
||||
p[i++].set( rect.x() + 0.5 * rect.width(), rect.y() + 0.5 * rect.height() );
|
||||
|
||||
BorderValuesNonUniform v( metrics );
|
||||
BorderValuesMulti v( metrics );
|
||||
|
||||
{
|
||||
constexpr auto id = TopLeft;
|
||||
@ -1424,7 +1428,7 @@ void QskBoxRenderer::renderRectellipseFill(
|
||||
#endif
|
||||
}
|
||||
|
||||
void QskBoxRenderer::renderRectellipse( const QRectF& rect,
|
||||
void QskRoundedRectRenderer::renderRectellipse( const QRectF& rect,
|
||||
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border,
|
||||
const QskBoxBorderColors& borderColors, const QskGradient& gradient,
|
||||
QSGGeometry& geometry )
|
||||
@ -1536,7 +1540,7 @@ void QskBoxRenderer::renderRectellipse( const QRectF& rect,
|
||||
{
|
||||
if ( metrics.isTotallyCropped )
|
||||
{
|
||||
renderRectFill( metrics.innerQuad, gradient, line );
|
||||
QskRectRenderer::renderFill0( metrics.innerQuad, gradient, line );
|
||||
}
|
||||
else if ( gradient.linearDirection().isTilted() )
|
||||
{
|
||||
@ -1572,7 +1576,7 @@ void QskBoxRenderer::renderRectellipse( const QRectF& rect,
|
||||
{
|
||||
if ( metrics.isTotallyCropped )
|
||||
{
|
||||
renderRectFill( metrics.innerQuad, gradient, line );
|
||||
QskRectRenderer::renderFill0( metrics.innerQuad, gradient, line );
|
||||
}
|
||||
else if ( gradient.linearDirection().isTilted() )
|
||||
{
|
62
src/nodes/QskRoundedRectRenderer.h
Normal file
62
src/nodes/QskRoundedRectRenderer.h
Normal file
@ -0,0 +1,62 @@
|
||||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_ROUNDED_RECT_RENDERER_H
|
||||
#define QSK_ROUNDED_RECT_RENDERER_H
|
||||
|
||||
#include "QskVertex.h"
|
||||
|
||||
class QskBoxBorderMetrics;
|
||||
class QskBoxBorderColors;
|
||||
class QskBoxShapeMetrics;
|
||||
class QskGradient;
|
||||
|
||||
class QSGGeometry;
|
||||
class QRectF;
|
||||
|
||||
namespace QskRoundedRectRenderer
|
||||
{
|
||||
class Metrics
|
||||
{
|
||||
public:
|
||||
Metrics( const QRectF&, const QskBoxShapeMetrics&, const QskBoxBorderMetrics& );
|
||||
|
||||
QskVertex::Quad outerQuad;
|
||||
QskVertex::Quad innerQuad;
|
||||
#if 1
|
||||
QskVertex::Quad centerQuad; // to be removed
|
||||
#endif
|
||||
|
||||
struct Corner
|
||||
{
|
||||
bool isCropped;
|
||||
qreal centerX, centerY;
|
||||
qreal radiusX, radiusY;
|
||||
qreal radiusInnerX, radiusInnerY;
|
||||
|
||||
int stepCount;
|
||||
|
||||
} corner[ 4 ];
|
||||
|
||||
bool isBorderRegular;
|
||||
bool isRadiusRegular;
|
||||
bool isTotallyCropped;
|
||||
};
|
||||
|
||||
void renderRectellipseFill( const QRectF&,
|
||||
const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, QSGGeometry& );
|
||||
|
||||
void renderRectellipseBorder( const QRectF&,
|
||||
const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, QSGGeometry& );
|
||||
|
||||
void renderRectellipse( const QRectF&,
|
||||
const QskBoxShapeMetrics&, const QskBoxBorderMetrics&,
|
||||
const QskBoxBorderColors&, const QskGradient&, QSGGeometry& );
|
||||
|
||||
void renderDiagonalFill( const Metrics&, const QskGradient&,
|
||||
int lineCount, QskVertex::ColoredLine* );
|
||||
}
|
||||
|
||||
#endif
|
@ -106,6 +106,8 @@ HEADERS += \
|
||||
nodes/QskBoxFillNode.h \
|
||||
nodes/QskBoxRectangleNode.h \
|
||||
nodes/QskBoxRenderer.h \
|
||||
nodes/QskRectRenderer.h \
|
||||
nodes/QskRoundedRectRenderer.h \
|
||||
nodes/QskBoxRendererColorMap.h \
|
||||
nodes/QskBoxShadowNode.h \
|
||||
nodes/QskColorRamp.h \
|
||||
@ -133,8 +135,8 @@ SOURCES += \
|
||||
nodes/QskBoxFillNode.cpp \
|
||||
nodes/QskBoxRectangleNode.cpp \
|
||||
nodes/QskBoxRenderer.cpp \
|
||||
nodes/QskBoxRendererRect.cpp \
|
||||
nodes/QskBoxRendererEllipse.cpp \
|
||||
nodes/QskRectRenderer.cpp \
|
||||
nodes/QskRoundedRectRenderer.cpp \
|
||||
nodes/QskBoxRendererDEllipse.cpp \
|
||||
nodes/QskBoxShadowNode.cpp \
|
||||
nodes/QskColorRamp.cpp \
|
||||
|
Loading…
x
Reference in New Issue
Block a user