codemoved to QskRoundedRect.hpp/QskRoundedRect.h

This commit is contained in:
Uwe Rathmann 2023-01-12 14:33:31 +01:00
parent c670d23582
commit a916bd78c2
8 changed files with 1180 additions and 865 deletions

View File

@ -241,10 +241,7 @@ namespace QskVertex
*/ */
if ( value > value0 ) if ( value > value0 )
{ contourIt.setGradientLine( value, colorIt.color(), l++ );
if ( contourIt.setGradientLine( value, colorIt.color(), l ) )
l++;
}
colorIt.advance(); colorIt.advance();
} }

View File

@ -5,6 +5,7 @@
#include "QskRoundedRectRenderer.h" #include "QskRoundedRectRenderer.h"
#include "QskBoxRendererColorMap.h" #include "QskBoxRendererColorMap.h"
#include "QskRoundedRect.h"
#include "QskGradient.h" #include "QskGradient.h"
#include "QskVertex.h" #include "QskVertex.h"
@ -44,7 +45,7 @@ namespace
class ValueCurve class ValueCurve
{ {
public: public:
ValueCurve( const QskRoundedRectRenderer::Metrics& m ) ValueCurve( const QskRoundedRect::Metrics& m )
{ {
/* /*
The slopes of the value line and those for the fill lines. The slopes of the value line and those for the fill lines.
@ -127,7 +128,7 @@ namespace
{ {
} }
void setup( const QskRoundedRectRenderer::Metrics& metrics, void setup( const QskRoundedRect::Metrics& metrics,
bool isLeading, bool clockwise, bool isLeading, bool clockwise,
qreal cos, qreal cosStep, qreal sin, qreal sinStep, qreal cos, qreal cosStep, qreal sin, qreal sinStep,
qreal x1, qreal y1, qreal v1, qreal x2, qreal y2, qreal v2 ) qreal x1, qreal y1, qreal v1, qreal x2, qreal y2, qreal v2 )
@ -168,7 +169,7 @@ namespace
inline const ContourLine& contourLine() const { return m_contourLine; } inline const ContourLine& contourLine() const { return m_contourLine; }
inline void advance( inline void advance(
const QskRoundedRectRenderer::Metrics& metrics, const QskRoundedRect::Metrics& metrics,
const ValueCurve& curve ) const ValueCurve& curve )
{ {
if ( m_isDone ) if ( m_isDone )
@ -320,7 +321,7 @@ namespace
static constexpr qreal m_eps = 1e-4; static constexpr qreal m_eps = 1e-4;
inline void setCorner( inline void setCorner(
Qt::Corner corner, const QskRoundedRectRenderer::Metrics& metrics ) Qt::Corner corner, const QskRoundedRect::Metrics& metrics )
{ {
m_corner = corner; m_corner = corner;
const auto& c = metrics.corner[ corner ]; const auto& c = metrics.corner[ corner ];
@ -414,7 +415,7 @@ namespace
class OutlineIterator class OutlineIterator
{ {
public: public:
OutlineIterator( const QskRoundedRectRenderer::Metrics& metrics, OutlineIterator( const QskRoundedRect::Metrics& metrics,
const ValueCurve& curve, bool clockwise ) const ValueCurve& curve, bool clockwise )
: m_metrics( metrics ) : m_metrics( metrics )
, m_curve( curve ) , m_curve( curve )
@ -551,7 +552,7 @@ namespace
line->setLine( x1, y1, x2, y2, color ); line->setLine( x1, y1, x2, y2, color );
} }
const QskRoundedRectRenderer::Metrics& m_metrics; const QskRoundedRect::Metrics& m_metrics;
const ValueCurve& m_curve; const ValueCurve& m_curve;
/* /*
@ -566,18 +567,16 @@ namespace
{ {
public: public:
DRectellipseIterator( DRectellipseIterator(
const QskRoundedRectRenderer::Metrics& metrics, const QskRoundedRect::Metrics& metrics, const ValueCurve& curve )
const ValueCurve& curve )
: m_left( metrics, curve, false ) : m_left( metrics, curve, false )
, m_right( metrics, curve, true ) , m_right( metrics, curve, true )
{ {
m_next = ( m_left.value() < m_right.value() ) ? &m_left : &m_right; m_next = ( m_left.value() < m_right.value() ) ? &m_left : &m_right;
} }
inline bool setGradientLine( qreal value, Color color, ColoredLine* line ) inline void setGradientLine( qreal value, Color color, ColoredLine* line )
{ {
m_next->setLineAt( value, color, line ); m_next->setLineAt( value, color, line );
return true;
} }
inline void setContourLine( Color color, ColoredLine* line ) inline void setContourLine( Color color, ColoredLine* line )
@ -604,7 +603,7 @@ namespace
}; };
} }
void QskRoundedRectRenderer::renderDiagonalFill( const QskRoundedRectRenderer::Metrics& metrics, void QskRoundedRectRenderer::renderDiagonalFill( const QskRoundedRect::Metrics& metrics,
const QskGradient& gradient, int fillLineCount, QskVertex::ColoredLine* lines ) const QskGradient& gradient, int fillLineCount, QskVertex::ColoredLine* lines )
{ {
const ValueCurve curve( metrics ); const ValueCurve curve( metrics );

View File

@ -41,7 +41,7 @@ namespace
} }
} }
inline bool setGradientLine( qreal value, Color color, ColoredLine* line ) inline void setGradientLine( qreal value, Color color, ColoredLine* line )
{ {
const auto v = m_t + value * m_dt; const auto v = m_t + value * m_dt;
@ -49,8 +49,6 @@ namespace
line->setHLine( m_rect.left, m_rect.right, v, color ); line->setHLine( m_rect.left, m_rect.right, v, color );
else else
line->setVLine( v, m_rect.top, m_rect.bottom, color ); line->setVLine( v, m_rect.top, m_rect.bottom, color );
return true;
} }
inline void setContourLine( Color color, ColoredLine* line ) inline void setContourLine( Color color, ColoredLine* line )
@ -127,7 +125,7 @@ namespace
qSwap( m_corners[1], m_corners[2] ); qSwap( m_corners[1], m_corners[2] );
} }
inline bool setGradientLine( qreal value, Color color, ColoredLine* line ) inline void setGradientLine( qreal value, Color color, ColoredLine* line )
{ {
const qreal m = m_v.dy / m_v.dx; const qreal m = m_v.dy / m_v.dx;
@ -198,8 +196,6 @@ namespace
line->setLine( p1.x(), p1.y(), p2.x(), p2.y(), color ); line->setLine( p1.x(), p1.y(), p2.x(), p2.y(), color );
else else
line->setLine( p2.x(), p2.y(), p1.x(), p1.y(), color ); line->setLine( p2.x(), p2.y(), p1.x(), p1.y(), color );
return true;
} }
inline void setContourLine( Color color, ColoredLine* line ) inline void setContourLine( Color color, ColoredLine* line )

182
src/nodes/QskRoundedRect.h Normal file
View File

@ -0,0 +1,182 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#ifndef QSK_SCALE_RENDERER_H
#define QSK_SCALE_RENDERER_H
#include "QskVertex.h"
#include "QskRoundedRectRenderer.h"
class QskBoxShapeMetrics;
class QskBoxBorderMetrics;
namespace QskRoundedRect
{
enum
{
TopLeft = Qt::TopLeftCorner,
TopRight = Qt::TopRightCorner,
BottomLeft = Qt::BottomLeftCorner,
BottomRight = Qt::BottomRightCorner
};
int additionalGradientStops( const QskGradient& );
int additionalGradientStops( const QskBoxBorderColors& );
class Metrics
{
public:
Metrics( const QRectF&, const QskBoxShapeMetrics&, const QskBoxBorderMetrics& );
QskVertex::Quad outerQuad;
QskVertex::Quad innerQuad;
QskVertex::Quad centerQuad;
struct Corner
{
bool isCropped;
qreal centerX, centerY;
qreal radiusX, radiusY;
qreal radiusInnerX, radiusInnerY;
int stepCount;
} corner[ 4 ];
bool isBorderRegular;
bool isRadiusRegular;
bool isTotallyCropped;
};
class BorderMapNone
{
public:
static inline constexpr QskVertex::Color colorAt( int ) { return QskVertex::Color(); }
inline QskGradient gradient() const { return QskGradient(); }
};
class BorderMapSolid
{
public:
inline BorderMapSolid( const QskVertex::Color color ): m_color( color ) {}
inline QskVertex::Color colorAt( int ) const { return m_color; }
inline QskGradient gradient() const { return QskGradient(); }
const QskVertex::Color m_color;
};
class BorderMapGradient
{
public:
BorderMapGradient( int stepCount,
const QskGradient& gradient1, const QskGradient& gradient2 )
: m_stepCount( stepCount )
, m_color1( gradient1.rgbStart() )
, m_color2( gradient2.rgbEnd() )
, m_gradient( gradient2 )
{
}
inline QskVertex::Color colorAt( int step ) const
{ return m_color1.interpolatedTo( m_color2, step / m_stepCount ); }
inline const QskGradient& gradient() const { return m_gradient; }
private:
const qreal m_stepCount;
const QskVertex::Color m_color1, m_color2;
const QskGradient m_gradient;
};
template< class T >
class BorderMaps
{
public:
BorderMaps( const T& );
BorderMaps( const T&, const T&, const T&, const T& );
int extraStops( int index ) const;
inline int extraStops() const;
T maps[4];
};
class BorderValues
{
public:
BorderValues( const Metrics& );
void setAngle( qreal cos, qreal sin );
qreal dx1( int pos ) const;
qreal dy1( int pos ) const;
qreal dx2( int pos ) const;
qreal dy2( int pos ) const;
private:
const Metrics& m_metrics;
const bool m_isUniform;
class Values
{
public:
inline void setAngle( qreal cos, qreal sin )
{
dx = x0 + cos * rx;
dy = y0 + sin * ry;
}
qreal dx, dy;
qreal x0, y0, rx, ry;
};
union
{
struct
{
Values inner[ 4 ];
Values outer[ 4 ];
} m_multi;
struct
{
qreal dx1, dy1, dx2, dy2;
} m_uniform;
};
};
template< class L >
class Stroker
{
public:
Stroker( const Metrics& );
void createBorderLines( L* ) const;
template< class FillMap >
void createFillLines( Qt::Orientation, L*, FillMap& ) const;
template< class BorderMap >
void createBorderLines( Qt::Orientation, L*,
const BorderMaps< BorderMap >& ) const;
template< class BorderMap, class FillMap >
inline void createUniformBox( Qt::Orientation, L*,
const BorderMaps< BorderMap >&, L*, FillMap& ) const;
private:
void setBorderGradientLine( const QskVertex::Line&,
float dx1, float dy1, float dx2, float dy2,
const QskGradientStop&, L* ) const;
void setBorderGradientLines( const BorderValues&,
int corner, const QskGradient&, L* ) const;
const Metrics& m_metrics;
};
}
#include "QskRoundedRect.hpp"
#endif

View File

@ -0,0 +1,884 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#ifndef QSK_SCALE_RENDERER_HPP
#define QSK_SCALE_RENDERER_HPP
#include "QskRoundedRectRenderer.h"
#include "QskBoxShapeMetrics.h"
#include "QskBoxBorderMetrics.h"
#include "QskBoxBorderColors.h"
#include <qsggeometry.h>
inline int QskRoundedRect::additionalGradientStops( const QskGradient& gradient )
{
return qMax( 0, gradient.stepCount() - 1 );
}
inline int QskRoundedRect::additionalGradientStops( const QskBoxBorderColors& bc )
{
return additionalGradientStops( bc.left() )
+ additionalGradientStops( bc.top() )
+ additionalGradientStops( bc.right() )
+ additionalGradientStops( bc.bottom() );
}
inline QskRoundedRect::Metrics::Metrics( const QRectF& rect,
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border )
: outerQuad( rect )
{
isRadiusRegular = shape.isRectellipse();
for ( int i = 0; i < 4; i++ )
{
auto& c = corner[ i ];
const QSizeF radius = shape.radius( static_cast< Qt::Corner >( i ) );
c.radiusX = qBound( 0.0, radius.width(), 0.5 * outerQuad.width );
c.radiusY = qBound( 0.0, radius.height(), 0.5 * outerQuad.height );
c.stepCount = ArcIterator::segmentHint( qMax( c.radiusX, c.radiusY ) );
switch ( i )
{
case TopLeft:
c.centerX = outerQuad.left + c.radiusX;
c.centerY = outerQuad.top + c.radiusY;
break;
case TopRight:
c.centerX = outerQuad.right - c.radiusX;
c.centerY = outerQuad.top + c.radiusY;
break;
case BottomLeft:
c.centerX = outerQuad.left + c.radiusX;
c.centerY = outerQuad.bottom - c.radiusY;
break;
case BottomRight:
c.centerX = outerQuad.right - c.radiusX;
c.centerY = outerQuad.bottom - c.radiusY;
break;
}
}
centerQuad.left = qMax( corner[ TopLeft ].centerX,
corner[ BottomLeft ].centerX );
centerQuad.right = qMin( corner[ TopRight ].centerX,
corner[ BottomRight ].centerX );
centerQuad.top = qMax( corner[ TopLeft ].centerY,
corner[ TopRight ].centerY );
centerQuad.bottom = qMin( corner[ BottomLeft ].centerY,
corner[ BottomRight ].centerY );
centerQuad.width = centerQuad.right - centerQuad.left;
centerQuad.height = centerQuad.bottom - centerQuad.top;
// now the bounding rectangle of the fill area
const auto bw = border.widths();
innerQuad.left = outerQuad.left + bw.left();
innerQuad.right = outerQuad.right - bw.right();
innerQuad.top = outerQuad.top + bw.top();
innerQuad.bottom = outerQuad.bottom - bw.bottom();
innerQuad.left = qMin( innerQuad.left, centerQuad.right );
innerQuad.right = qMax( innerQuad.right, centerQuad.left );
innerQuad.top = qMin( innerQuad.top, centerQuad.bottom );
innerQuad.bottom = qMax( innerQuad.bottom, centerQuad.top );
if ( innerQuad.left > innerQuad.right )
{
innerQuad.left = innerQuad.right =
innerQuad.right + 0.5 * ( innerQuad.left - innerQuad.right );
}
if ( innerQuad.top > innerQuad.bottom )
{
innerQuad.top = innerQuad.bottom =
innerQuad.bottom + 0.5 * ( innerQuad.top - innerQuad.bottom );
}
innerQuad.width = innerQuad.right - innerQuad.left;
innerQuad.height = innerQuad.bottom - innerQuad.top;
const qreal borderLeft = innerQuad.left - outerQuad.left;
const qreal borderTop = innerQuad.top - outerQuad.top;
const qreal borderRight = outerQuad.right - innerQuad.right;
const qreal borderBottom = outerQuad.bottom - innerQuad.bottom;
for ( int i = 0; i < 4; i++ )
{
auto& c = corner[ i ];
switch ( i )
{
case TopLeft:
{
c.radiusInnerX = c.radiusX - borderLeft;
c.radiusInnerY = c.radiusY - borderTop;
c.isCropped = ( c.centerX <= innerQuad.left ) ||
( c.centerY <= innerQuad.top );
break;
}
case TopRight:
{
c.radiusInnerX = c.radiusX - borderRight;
c.radiusInnerY = c.radiusY - borderTop;
c.isCropped = ( c.centerX >= innerQuad.right ) ||
( c.centerY <= innerQuad.top );
break;
}
case BottomLeft:
{
c.radiusInnerX = c.radiusX - borderLeft;
c.radiusInnerY = c.radiusY - borderBottom;
c.isCropped = ( c.centerX <= innerQuad.left ) ||
( c.centerY >= innerQuad.bottom );
break;
}
case BottomRight:
{
c.radiusInnerX = c.radiusX - borderRight;
c.radiusInnerY = c.radiusY - borderBottom;
c.isCropped = ( c.centerX >= innerQuad.right ) ||
( c.centerY >= innerQuad.bottom );
break;
}
}
}
isTotallyCropped =
corner[ TopLeft ].isCropped &&
corner[ TopRight ].isCropped &&
corner[ BottomRight ].isCropped &&
corner[ BottomLeft ].isCropped;
// number of steps for iterating over the corners
isBorderRegular =
( borderLeft == borderTop ) &&
( borderTop == borderRight ) &&
( borderRight == borderBottom );
}
template< class T >
inline QskRoundedRect::BorderMaps< T >::BorderMaps( const T& map )
: maps{ map, map, map, map }
{
}
template< class T >
inline QskRoundedRect::BorderMaps< T >::BorderMaps(
const T& tl, const T& tr, const T& bl, const T& br )
: maps{ tl, tr, bl, br }
{
}
template< class T >
inline int QskRoundedRect::BorderMaps< T >::extraStops( int index ) const
{
return additionalGradientStops( maps[index].gradient() );
}
template< class T >
inline int QskRoundedRect::BorderMaps< T >::extraStops() const
{
return extraStops( 0 ) + extraStops( 1 ) + extraStops( 2 ) + extraStops( 3 );
}
inline QskRoundedRect::BorderValues::BorderValues(
const QskRoundedRect::Metrics& metrics )
: m_metrics( metrics )
, m_isUniform( metrics.isBorderRegular && metrics.isRadiusRegular )
{
if ( m_isUniform )
{
const auto& c = metrics.corner[ 0 ];
m_uniform.dx1 = c.radiusInnerX;
m_uniform.dy1 = c.radiusInnerY;
}
else
{
for ( int i = 0; i < 4; i++ )
{
const auto& c = metrics.corner[ i ];
auto& inner = m_multi.inner[ i ];
auto& outer = m_multi.outer[ i ];
if ( c.radiusInnerX >= 0.0 )
{
inner.x0 = 0.0;
inner.rx = c.radiusInnerX;
}
else
{
// should also be c.isCropped !
inner.x0 = c.radiusInnerX;
inner.rx = 0.0;
}
if ( c.radiusInnerY >= 0.0 )
{
inner.y0 = 0.0;
inner.ry = c.radiusInnerY;
}
else
{
// should also be c.isCropped !
inner.y0 = c.radiusInnerY;
inner.ry = 0.0;
}
outer.x0 = outer.y0 = 0.0;
outer.rx = c.radiusX;
outer.ry = c.radiusY;
}
}
}
inline void QskRoundedRect::BorderValues::setAngle( qreal cos, qreal sin )
{
if ( m_isUniform )
{
const auto& c = m_metrics.corner[ 0 ];
if ( !c.isCropped )
{
m_uniform.dx1 = cos * c.radiusInnerX;
m_uniform.dy1 = sin * c.radiusInnerY;
}
m_uniform.dx2 = cos * c.radiusX;
m_uniform.dy2 = sin * c.radiusY;
}
else
{
auto inner = m_multi.inner;
auto outer = m_multi.outer;
inner[ 0 ].setAngle( cos, sin );
inner[ 1 ].setAngle( cos, sin );
inner[ 2 ].setAngle( cos, sin );
inner[ 3 ].setAngle( cos, sin );
outer[ 0 ].setAngle( cos, sin );
if ( !m_metrics.isRadiusRegular )
{
outer[ 1 ].setAngle( cos, sin );
outer[ 2 ].setAngle( cos, sin );
outer[ 3 ].setAngle( cos, sin );
}
}
}
inline qreal QskRoundedRect::BorderValues::dx1( int pos ) const
{
return m_isUniform ? m_uniform.dx1 : m_multi.inner[ pos].dx;
}
inline qreal QskRoundedRect::BorderValues::dy1( int pos ) const
{
return m_isUniform ? m_uniform.dy1 : m_multi.inner[ pos ].dy;
}
inline qreal QskRoundedRect::BorderValues::dx2( int pos ) const
{
if ( m_isUniform )
return m_uniform.dx2;
const auto outer = m_multi.outer;
return m_metrics.isRadiusRegular ? outer[ 0 ].dx : outer[ pos ].dx;
}
inline qreal QskRoundedRect::BorderValues::dy2( int pos ) const
{
if ( m_isUniform )
return m_uniform.dy2;
const auto outer = m_multi.outer;
return m_metrics.isRadiusRegular ? outer[ 0 ].dy : outer[ pos ].dy;
}
template< class L >
inline QskRoundedRect::Stroker< L >::Stroker( const QskRoundedRect::Metrics& metrics )
: m_metrics( metrics )
{
}
template< class L >
inline void QskRoundedRect::Stroker< L >::setBorderGradientLine(
const QskVertex::Line& l, float dx1, float dy1, float dx2, float dy2,
const QskGradientStop& stop, L* line ) const
{
const auto pos = stop.position();
const float x1 = l.p1.x + pos * dx1;
const float y1 = l.p1.y + pos * dy1;
const float x2 = l.p2.x + pos * dx2;
const float y2 = l.p2.y + pos * dy2;
line->setLine( x1, y1, x2, y2, stop.rgb() );
}
template< class L >
inline void QskRoundedRect::Stroker< L >::setBorderGradientLines( const BorderValues& v, int c1,
const QskGradient& gradient, L* lines ) const
{
if( gradient.stepCount() <= 1 )
{
// everything done as contour lines
return;
}
QskVertex::Line from, to;
const auto& c = m_metrics.corner;
switch( c1 )
{
case TopLeft:
{
const auto c2 = BottomLeft;
to.p1.x = c[ c1 ].centerX - v.dx1( c1 );
to.p1.y = c[ c1 ].centerY - v.dy1( c1 );
to.p2.x = c[ c1 ].centerX - v.dx2( c1 );
to.p2.y = c[ c1 ].centerY - v.dy2( c1 );
from.p1.x = c[ c2 ].centerX - v.dx1( c2 );
from.p1.y = c[ c2 ].centerY + v.dy1( c2 );
from.p2.x = c[ c2 ].centerX - v.dx2( c2 );
from.p2.y = c[ c2 ].centerY + v.dy2( c2 );
break;
}
case TopRight:
{
const auto c2 = TopLeft;
to.p1.x = c[ c1 ].centerX + v.dx1( c1 );
to.p1.y = c[ c1 ].centerY - v.dy1( c1 );
to.p2.x = c[ c1 ].centerX + v.dx2( c1 );
to.p2.y = c[ c1 ].centerY - v.dy2( c1 );
from.p1.x = c[ c2 ].centerX - v.dx1( c2 );
from.p1.y = c[ c2 ].centerY - v.dy1( c2 );
from.p2.x = c[ c2 ].centerX - v.dx2( c2 );
from.p2.y = c[ c2 ].centerY - v.dy2( c2 );
break;
}
case BottomLeft:
{
const auto c2 = BottomRight;
to.p1.x = c[ c1 ].centerX - v.dx1( c1 );
to.p1.y = c[ c1 ].centerY + v.dy1( c1 );
to.p2.x = c[ c1 ].centerX - v.dx2( c1 );
to.p2.y = c[ c1 ].centerY + v.dy2( c1 );
from.p1.x = c[ c2 ].centerX + v.dx1( c2 );
from.p1.y = c[ c2 ].centerY + v.dy1( c2 );
from.p2.x = c[ c2 ].centerX + v.dx2( c2 );
from.p2.y = c[ c2 ].centerY + v.dy2( c2 );
break;
}
case BottomRight:
{
const auto c2 = TopRight;
to.p1.x = c[ c1 ].centerX + v.dx1( c1 );
to.p1.y = c[ c1 ].centerY + v.dy1( c1 );
to.p2.x = c[ c1 ].centerX + v.dx2( c1 );
to.p2.y = c[ c1 ].centerY + v.dy2( c1 );
from.p1.x = c[ c2 ].centerX + v.dx1( c2 );
from.p1.y = c[ c2 ].centerY - v.dy1( c2 );
from.p2.x = c[ c2 ].centerX + v.dx2( c2 );
from.p2.y = c[ c2 ].centerY - v.dy2( c2 );
break;
}
}
const float dx1 = to.p1.x - from.p1.x;
const float dy1 = to.p1.y - from.p1.y;
const float dx2 = to.p2.x - from.p2.x;
const float dy2 = to.p2.y - from.p2.y;
const auto stops = gradient.stops();
auto line = lines;
{
const auto& stop = stops.last();
if ( stop.position() < 1.0 )
setBorderGradientLine( from, dx1, dy1, dx2, dy2, stop, line++ );
}
for( int i = stops.count() - 2; i >= 1; i-- )
setBorderGradientLine( from, dx1, dy1, dx2, dy2, stops[i], line++ );
{
const auto& stop = stops.first();
if ( stop.position() > 0.0 )
setBorderGradientLine( from, dx1, dy1, dx2, dy2, stop, line++ );
}
}
template< class L >
inline void QskRoundedRect::Stroker< L >::createBorderLines( L* lines ) const
{
Q_ASSERT( m_metrics.isRadiusRegular );
const auto& c = m_metrics.corner;
const int stepCount = c[ 0 ].stepCount;
const int numCornerLines = stepCount + 1;
L* linesBR = lines;
L* linesTR = linesBR + numCornerLines;
L* linesTL = linesTR + numCornerLines;
L* linesBL = linesTL + numCornerLines;
BorderValues v( m_metrics );
/*
It would be possible to run over [0, 0.5 * M_PI_2]
and create 8 values ( instead of 4 ) in each step. TODO ...
*/
for ( ArcIterator it( stepCount, false ); !it.isDone(); ++it )
{
v.setAngle( it.cos(), it.sin() );
const int j = it.step();
const int k = numCornerLines - it.step() - 1;
{
constexpr auto corner = TopLeft;
linesTL[ j ].setLine(
c[ corner ].centerX - v.dx1( corner ),
c[ corner ].centerY - v.dy1( corner ),
c[ corner ].centerX - v.dx2( corner ),
c[ corner ].centerY - v.dy2( corner ) );
}
{
constexpr auto corner = TopRight;
linesTR[ k ].setLine(
c[ corner ].centerX + v.dx1( corner ),
c[ corner ].centerY - v.dy1( corner ),
c[ corner ].centerX + v.dx2( corner ),
c[ corner ].centerY - v.dy2( corner ) );
}
{
constexpr auto corner = BottomLeft;
linesBL[ k ].setLine(
c[ corner ].centerX - v.dx1( corner ),
c[ corner ].centerY + v.dy1( corner ),
c[ corner ].centerX - v.dx2( corner ),
c[ corner ].centerY + v.dy2( corner ) );
}
{
constexpr auto corner = BottomRight;
linesBR[ j ].setLine(
c[ corner ].centerX + v.dx1( corner ),
c[ corner ].centerY + v.dy1( corner ),
c[ corner ].centerX + v.dx2( corner ),
c[ corner ].centerY + v.dy2( corner ) );
}
}
lines[ 4 * numCornerLines ] = lines[ 0 ];
}
template< class L > template< class FillMap >
inline void QskRoundedRect::Stroker< L >::createFillLines(
Qt::Orientation orientation, L* lines, FillMap& fillMap ) const
{
Q_ASSERT( m_metrics.isRadiusRegular );
const auto& c = m_metrics.corner;
const int stepCount = c[ 0 ].stepCount;
int numLines = 2 * stepCount + 1;
if ( orientation == Qt::Vertical )
{
if ( m_metrics.centerQuad.top < m_metrics.centerQuad.bottom )
numLines++;
}
else
{
if ( m_metrics.centerQuad.left < m_metrics.centerQuad.right )
numLines++;
}
BorderValues v( m_metrics );
/*
It would be possible to run over [0, 0.5 * M_PI_2]
and create 8 values ( instead of 4 ) in each step. TODO ...
*/
for ( ArcIterator it( stepCount, false ); !it.isDone(); ++it )
{
v.setAngle( it.cos(), it.sin() );
const auto& ri = m_metrics.innerQuad;
if ( orientation == Qt::Vertical )
{
const int j = it.step();
const int k = numLines - it.step() - 1;
const qreal x11 = c[ TopLeft ].centerX - v.dx1( TopLeft );
const qreal x12 = c[ TopRight ].centerX + v.dx1( TopRight );
const qreal y1 = c[ TopLeft ].centerY - v.dy1( TopLeft );
const auto c1 = fillMap.colorAt( ( y1 - ri.top ) / ri.height );
const qreal x21 = c[ BottomLeft ].centerX - v.dx1( BottomLeft );
const qreal x22 = c[ BottomRight ].centerX + v.dx1( BottomRight );
const qreal y2 = c[ BottomLeft ].centerY + v.dy1( BottomLeft );
const auto c2 = fillMap.colorAt( ( y2 - ri.top ) / ri.height );
lines[ j ].setLine( x11, y1, x12, y1, c1 );
lines[ k ].setLine( x21, y2, x22, y2, c2 );
}
else
{
const int j = stepCount - it.step();
const int k = numLines - 1 - stepCount + it.step();
const qreal x1 = c[ TopLeft ].centerX - v.dx1( TopLeft );
const qreal y11 = c[ TopLeft ].centerY - v.dy1( TopLeft );
const qreal y12 = c[ BottomLeft ].centerY + v.dy1( BottomLeft );
const auto c1 = fillMap.colorAt( ( x1 - ri.left ) / ri.width );
const qreal x2 = c[ TopRight ].centerX + v.dx1( TopRight );
const qreal y21 = c[ TopRight ].centerY - v.dy1( TopRight );
const qreal y22 = c[ BottomRight ].centerY + v.dy1( BottomRight );
const auto c2 = fillMap.colorAt( ( x2 - ri.left ) / ri.width );
lines[ j ].setLine( x1, y11, x1, y12, c1 );
lines[ k ].setLine( x2, y21, x2, y22, c2 );
}
}
}
template< class L >
template< class BorderMap >
inline void QskRoundedRect::Stroker< L >::createBorderLines(
Qt::Orientation orientation, L* borderLines,
const BorderMaps< BorderMap >& borderMaps ) const
{
const auto& c = m_metrics.corner;
#if 1
// not correct for BorderValuesMulti TODO ...
const int stepCount = c[ 0 ].stepCount;
#endif
L* linesBR, * linesTR, * linesTL, * linesBL;
const int numCornerLines = stepCount + 1;
if ( orientation == Qt::Vertical )
{
linesBR = borderLines;
linesTR = linesBR + numCornerLines + borderMaps.extraStops( BottomRight );
linesTL = linesTR + numCornerLines + borderMaps.extraStops( TopRight );
linesBL = linesTL + numCornerLines + borderMaps.extraStops( TopLeft );
}
else
{
linesTR = borderLines + 1;
linesTL = linesTR + numCornerLines + borderMaps.extraStops( TopRight );
linesBL = linesTL + numCornerLines + borderMaps.extraStops( TopLeft );
linesBR = linesBL + numCornerLines + borderMaps.extraStops( BottomLeft );
}
BorderValues v( m_metrics );
/*
It would be possible to run over [0, 0.5 * M_PI_2]
and create 8 values ( instead of 4 ) in each step. TODO ...
*/
for ( ArcIterator it( stepCount, false ); !it.isDone(); ++it )
{
v.setAngle( it.cos(), it.sin() );
const int j = it.step();
const int k = numCornerLines - it.step() - 1;
{
constexpr auto corner = TopLeft;
linesTL[ j ].setLine(
c[ corner ].centerX - v.dx1( corner ),
c[ corner ].centerY - v.dy1( corner ),
c[ corner ].centerX - v.dx2( corner ),
c[ corner ].centerY - v.dy2( corner ),
borderMaps.maps[ corner ].colorAt( j ) );
}
{
constexpr auto corner = TopRight;
linesTR[ k ].setLine(
c[ corner ].centerX + v.dx1( corner ),
c[ corner ].centerY - v.dy1( corner ),
c[ corner ].centerX + v.dx2( corner ),
c[ corner ].centerY - v.dy2( corner ),
borderMaps.maps[ corner ].colorAt( k ) );
}
{
constexpr auto corner = BottomLeft;
linesBL[ k ].setLine(
c[ corner ].centerX - v.dx1( corner ),
c[ corner ].centerY + v.dy1( corner ),
c[ corner ].centerX - v.dx2( corner ),
c[ corner ].centerY + v.dy2( corner ),
borderMaps.maps[ corner ].colorAt( k ) );
}
{
constexpr auto corner = BottomRight;
linesBR[ j ].setLine(
c[ corner ].centerX + v.dx1( corner ),
c[ corner ].centerY + v.dy1( corner ),
c[ corner ].centerX + v.dx2( corner ),
c[ corner ].centerY + v.dy2( corner ),
borderMaps.maps[ corner ].colorAt( j ) );
}
}
v.setAngle( 0.0, 1.0 );
setBorderGradientLines( v, TopRight,
borderMaps.maps[ TopRight ].gradient(), linesTR + numCornerLines );
setBorderGradientLines( v, BottomLeft,
borderMaps.maps[ BottomLeft ].gradient(), linesBL + numCornerLines );
v.setAngle( 1.0, 0.0 );
setBorderGradientLines( v, TopLeft,
borderMaps.maps[ TopLeft ].gradient(), linesTL + numCornerLines );
setBorderGradientLines( v, BottomRight,
borderMaps.maps[ BottomRight ].gradient(), linesBR + numCornerLines );
const int k = 4 * numCornerLines + borderMaps.extraStops();
if ( orientation == Qt::Vertical )
borderLines[ k ] = borderLines[ 0 ];
else
borderLines[ 0 ] = borderLines[ k ];
}
template< class L >
template< class BorderMap, class FillMap >
inline void QskRoundedRect::Stroker< L >::createUniformBox(
Qt::Orientation orientation, L* borderLines,
const BorderMaps< BorderMap >& borderMaps, L* fillLines, FillMap& fillMap ) const
{
Q_ASSERT( m_metrics.isRadiusRegular );
const auto& c = m_metrics.corner;
const int stepCount = c[ 0 ].stepCount;
L* linesBR, * linesTR, * linesTL, * linesBL;
linesBR = linesTR = linesTL = linesBL = nullptr;
const int numCornerLines = stepCount + 1;
int numFillLines = fillLines ? 2 * numCornerLines : 0;
if ( orientation == Qt::Vertical )
{
if ( borderLines )
{
linesBR = borderLines;
linesTR = linesBR + numCornerLines + borderMaps.extraStops( BottomRight );
linesTL = linesTR + numCornerLines + borderMaps.extraStops( TopRight );
linesBL = linesTL + numCornerLines + borderMaps.extraStops( TopLeft );
}
if ( fillLines )
{
if ( m_metrics.centerQuad.top >= m_metrics.centerQuad.bottom )
numFillLines--;
}
}
else
{
if ( borderLines )
{
linesTR = borderLines + 1;
linesTL = linesTR + numCornerLines + borderMaps.extraStops( TopRight );
linesBL = linesTL + numCornerLines + borderMaps.extraStops( TopLeft );
linesBR = linesBL + numCornerLines + borderMaps.extraStops( BottomLeft );
}
if ( fillLines )
{
if ( m_metrics.centerQuad.left >= m_metrics.centerQuad.right )
numFillLines--;
}
}
BorderValues v( m_metrics );
/*
It would be possible to run over [0, 0.5 * M_PI_2]
and create 8 values ( instead of 4 ) in each step. TODO ...
*/
for ( ArcIterator it( stepCount, false ); !it.isDone(); ++it )
{
v.setAngle( it.cos(), it.sin() );
if ( borderLines )
{
const int j = it.step();
const int k = numCornerLines - it.step() - 1;
{
constexpr auto corner = TopLeft;
linesTL[ j ].setLine(
c[ corner ].centerX - v.dx1( corner ),
c[ corner ].centerY - v.dy1( corner ),
c[ corner ].centerX - v.dx2( corner ),
c[ corner ].centerY - v.dy2( corner ),
borderMaps.maps[ corner ].colorAt( j ) );
}
{
constexpr auto corner = TopRight;
linesTR[ k ].setLine(
c[ corner ].centerX + v.dx1( corner ),
c[ corner ].centerY - v.dy1( corner ),
c[ corner ].centerX + v.dx2( corner ),
c[ corner ].centerY - v.dy2( corner ),
borderMaps.maps[ corner ].colorAt( k ) );
}
{
constexpr auto corner = BottomLeft;
linesBL[ k ].setLine(
c[ corner ].centerX - v.dx1( corner ),
c[ corner ].centerY + v.dy1( corner ),
c[ corner ].centerX - v.dx2( corner ),
c[ corner ].centerY + v.dy2( corner ),
borderMaps.maps[ corner ].colorAt( k ) );
}
{
constexpr auto corner = BottomRight;
linesBR[ j ].setLine(
c[ corner ].centerX + v.dx1( corner ),
c[ corner ].centerY + v.dy1( corner ),
c[ corner ].centerX + v.dx2( corner ),
c[ corner ].centerY + v.dy2( corner ),
borderMaps.maps[ corner ].colorAt( j ) );
}
}
if ( fillLines )
{
const auto& ri = m_metrics.innerQuad;
if ( orientation == Qt::Vertical )
{
const int j = it.step();
const int k = numFillLines - it.step() - 1;
const qreal x11 = c[ TopLeft ].centerX - v.dx1( TopLeft );
const qreal x12 = c[ TopRight ].centerX + v.dx1( TopRight );
const qreal y1 = c[ TopLeft ].centerY - v.dy1( TopLeft );
const auto c1 = fillMap.colorAt( ( y1 - ri.top ) / ri.height );
const qreal x21 = c[ BottomLeft ].centerX - v.dx1( BottomLeft );
const qreal x22 = c[ BottomRight ].centerX + v.dx1( BottomRight );
const qreal y2 = c[ BottomLeft ].centerY + v.dy1( BottomLeft );
const auto c2 = fillMap.colorAt( ( y2 - ri.top ) / ri.height );
fillLines[ j ].setLine( x11, y1, x12, y1, c1 );
fillLines[ k ].setLine( x21, y2, x22, y2, c2 );
}
else
{
const int j = stepCount - it.step();
const int k = numFillLines - 1 - stepCount + it.step();
const qreal x1 = c[ TopLeft ].centerX - v.dx1( TopLeft );
const qreal y11 = c[ TopLeft ].centerY - v.dy1( TopLeft );
const qreal y12 = c[ BottomLeft ].centerY + v.dy1( BottomLeft );
const auto c1 = fillMap.colorAt( ( x1 - ri.left ) / ri.width );
const qreal x2 = c[ TopRight ].centerX + v.dx1( TopRight );
const qreal y21 = c[ TopRight ].centerY - v.dy1( TopRight );
const qreal y22 = c[ BottomRight ].centerY + v.dy1( BottomRight );
const auto c2 = fillMap.colorAt( ( x2 - ri.left ) / ri.width );
fillLines[ j ].setLine( x1, y11, x1, y12, c1 );
fillLines[ k ].setLine( x2, y21, x2, y22, c2 );
}
}
}
if ( borderLines )
{
v.setAngle( 0.0, 1.0 );
setBorderGradientLines( v, TopRight,
borderMaps.maps[ TopRight ].gradient(), linesTR + numCornerLines );
setBorderGradientLines( v, BottomLeft,
borderMaps.maps[ BottomLeft ].gradient(), linesBL + numCornerLines );
v.setAngle( 1.0, 0.0 );
setBorderGradientLines( v, TopLeft,
borderMaps.maps[ TopLeft ].gradient(), linesTL + numCornerLines );
setBorderGradientLines( v, BottomRight,
borderMaps.maps[ BottomRight ].gradient(), linesBR + numCornerLines );
const int k = 4 * numCornerLines + borderMaps.extraStops();
if ( orientation == Qt::Vertical )
borderLines[ k ] = borderLines[ 0 ];
else
borderLines[ 0 ] = borderLines[ k ];
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -16,33 +16,10 @@ class QskGradient;
class QSGGeometry; class QSGGeometry;
class QRectF; class QRectF;
namespace QskRoundedRect { class Metrics; }
namespace QskRoundedRectRenderer namespace QskRoundedRectRenderer
{ {
class Metrics
{
public:
Metrics( const QRectF&, const QskBoxShapeMetrics&, const QskBoxBorderMetrics& );
QskVertex::Quad outerQuad;
QskVertex::Quad innerQuad;
QskVertex::Quad centerQuad;
struct Corner
{
bool isCropped;
qreal centerX, centerY;
qreal radiusX, radiusY;
qreal radiusInnerX, radiusInnerY;
int stepCount;
} corner[ 4 ];
bool isBorderRegular;
bool isRadiusRegular;
bool isTotallyCropped;
};
void renderFillGeometry( const QRectF&, void renderFillGeometry( const QRectF&,
const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, QSGGeometry& ); const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, QSGGeometry& );
@ -54,8 +31,8 @@ namespace QskRoundedRectRenderer
const QskBoxBorderColors&, const QskGradient&, QSGGeometry& ); const QskBoxBorderColors&, const QskGradient&, QSGGeometry& );
// QskBoxRendererDEllipse.cpp // QskBoxRendererDEllipse.cpp
void renderDiagonalFill( const Metrics&, const QskGradient&, void renderDiagonalFill( const QskRoundedRect::Metrics&,
int lineCount, QskVertex::ColoredLine* ); const QskGradient&, int lineCount, QskVertex::ColoredLine* );
} }
#endif #endif

View File

@ -108,6 +108,8 @@ HEADERS += \
nodes/QskBoxRenderer.h \ nodes/QskBoxRenderer.h \
nodes/QskRectRenderer.h \ nodes/QskRectRenderer.h \
nodes/QskRoundedRectRenderer.h \ nodes/QskRoundedRectRenderer.h \
nodes/QskRoundedRect.h \
nodes/QskRoundedRect.hpp \
nodes/QskBoxRendererColorMap.h \ nodes/QskBoxRendererColorMap.h \
nodes/QskBoxShadowNode.h \ nodes/QskBoxShadowNode.h \
nodes/QskColorRamp.h \ nodes/QskColorRamp.h \