Box renderer: Support border gradients (#158)

* QskBoxBorderColors: Use gradients instead of colors

* QskBoxBorderColors: rename API

* render gradients on borders

* boxes example: Also draw gradient borders

* calculate proper numbers of needed border colors

* fixup with example

* support rounded corners

* support more colors in rounded color gradients

I THINK WE DON'T REALLY NEED THIS COMMIT

* We don't need this commit either

* Revert "We don't need this commit either"

This reverts commit 2dc38064f7fee1d0505262fe5cebcf9e1fb16cea.

* Revert "support more colors in rounded color gradients"

This reverts commit 5754d2d0773d8273d42ae1775b53d40f5e6af26a.

* fix borders for rect ellipses

* play around a bit

* small fixes

* some helper stuff and missing stuff

* user border colors

* close to something working somehow

* works a bit better

* put it into an own function

* rearrange a bit

* something's off

* still off, but seems like we need an additional line

* works but hackish

* now it works

* bring back samples

* correction

* pimp up example

* fix normal rendering

* some more debugging etc.

* turn around gradients

* turn around rectangular gradients as well

* turn around easier

* more test cases

* fix fill case

* more test cases

* clean up a bit

* clean up example

* clean up some more

* incorporate feedback from Uwe

* fix bug when using horizontal gradients
This commit is contained in:
Peter Hartmann 2022-02-04 16:11:11 +01:00 committed by GitHub
parent 4c7c369477
commit ac8ef9cd5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 496 additions and 180 deletions

View File

@ -80,23 +80,23 @@ void Box::setBorder( BorderType type, QskRgbPalette::Theme theme )
break;
case Flat:
setBorderColor( mid );
setBorderGradient( mid );
break;
case Raised1:
setBorderColors( light, light, dark, dark );
setBorderGradients( light, light, dark, dark );
break;
case Sunken1:
setBorderColors( dark, dark, light, light );
setBorderGradients( dark, dark, light, light );
break;
case Raised2:
setBorderColors( mid, light, mid, dark );
setBorderGradients( mid, light, mid, dark );
break;
case Sunken2:
setBorderColors( mid, dark, mid, light );
setBorderGradients( mid, dark, mid, light );
break;
}
}
@ -117,16 +117,16 @@ void Box::setShape( qreal radiusX, qreal radiusY, Qt::SizeMode sizeMode )
QskBoxShapeMetrics( radiusX, radiusY, sizeMode ) );
}
void Box::setBorderColors( const QColor& left, const QColor& top,
const QColor& right, const QColor& bottom )
void Box::setBorderGradients( const QskGradient& left, const QskGradient& top,
const QskGradient& right, const QskGradient& bottom )
{
QskBoxBorderColors colors( left, top, right, bottom );
setBoxBorderColorsHint( QskBox::Panel, colors );
}
void Box::setBorderColor( const QColor& color )
void Box::setBorderGradient( const QskGradient& gradient )
{
setBoxBorderColorsHint( QskBox::Panel, color );
setBoxBorderColorsHint( QskBox::Panel, gradient );
}
void Box::setBorderWidth( qreal left, qreal top, qreal right, qreal bottom )

View File

@ -39,9 +39,9 @@ class Box : public QskBox
void setShape( qreal radius, Qt::SizeMode );
void setShape( qreal radiusX, qreal radiusY, Qt::SizeMode );
void setBorderColor( const QColor& );
void setBorderColors( const QColor& left, const QColor& top,
const QColor& right, const QColor& bottom );
void setBorderGradient( const QskGradient& );
void setBorderGradients( const QskGradient& left, const QskGradient& top,
const QskGradient& right, const QskGradient& bottom );
void setBorderWidth( int );
void setBorderWidth( qreal left, qreal top, qreal right, qreal bottom );

View File

@ -232,25 +232,25 @@ static void addRectangles10( QskLinearBox* parent )
box = new Box( parent );
box->setBorderWidth( 10 );
box->setBorderColor( borderTheme );
box->setBorderGradient( borderTheme );
box->setGradient( QskGradient::Diagonal, "DeepPink", "DarkOrange", "HotPink" );
box = new Box( parent );
box->setShape( 100, Qt::RelativeSize );
box->setBorderWidth( 5 );
box->setBorderColor( borderTheme );
box->setBorderGradient( borderTheme );
box->setGradient( QskGradient::Vertical, "DeepPink", "DarkOrange", "HotPink" );
box = new Box( parent );
box->setShape( 100, Qt::RelativeSize );
box->setBorderWidth( 5 );
box->setBorderColor( borderTheme );
box->setBorderGradient( borderTheme );
box->setGradient( QskGradient::Diagonal, "DeepPink", "DarkOrange", "HotPink" );
box = new Box( parent );
box->setShape( 100, Qt::RelativeSize );
box->setBorderWidth( 5, 20, 30, 5 );
box->setBorderColor( borderTheme );
box->setBorderGradient( borderTheme );
box->setGradient( QskGradient::Vertical, "DeepPink", "DarkOrange", "HotPink" );
}
@ -333,32 +333,127 @@ static void addRectanglesRest( QskLinearBox* parent )
box = new Box( parent );
box->setBorderWidth( 20, 0, 40, 0 );
box->setBorderColor( "DarkSeaGreen" );
box->setBorderGradient( { "DarkSeaGreen" } );
box = new Box( parent );
box->setShape( 40, Qt::RelativeSize );
box->setBorderWidth( 20, 10, 30, 15 );
box->setBorderColor( "DarkOrange" );
box->setBorderGradient( { "DarkOrange" } );
box->setGradient( QskGradient::Vertical, "LightSteelBlue", "SteelBlue" );
box = new Box( parent );
box->setBorderWidth( 20, 0, 10, 20 );
box->setBorderColor( "MediumSeaGreen" );
box->setBorderGradient( { "MediumSeaGreen" } );
box->setGradient( "DodgerBlue" );
box = new Box( parent );
box->setShape( 20, Qt::AbsoluteSize );
box->setBorderWidth( 2, 10, 40, 2 );
box->setBorderColor( "Crimson" );
box->setBorderGradient( { "Crimson" } );
box->setGradient( QskRgb::WhiteSmoke );
box = new Box( parent );
box->setShape( 100, Qt::RelativeSize );
box->setBorderWidth( 5, 20, 5, 0 );
box->setBorderColor( "CadetBlue" );
box->setBorderGradient( { "CadetBlue" } );
box->setGradient( QskGradient::Vertical, "Gainsboro", "Seashell", "LightGray" );
}
static void addColoredBorderRectangles1( QskLinearBox* parent, bool rounded, Box::FillType fillType )
{
auto* box = new Box( parent );
box->setBorderWidth( 20 );
QskGradient gradient1( Qt::Vertical, { { 0.0, Qt::blue },
{ 0.9, Qt::yellow },
{ 1.0, Qt::darkRed } } );
QskGradient gradient2( Qt::Vertical, { { 0.0, Qt::black },
{ 0.3, Qt::white },
{ 0.7, Qt::white },
{ 1.0, Qt::black } } );
QskGradient gradient3( Qt::green );
QskGradient gradient4( Qt::Vertical, Qt::magenta, Qt::cyan );
box->setBorderGradients( gradient1, gradient2, gradient3, gradient4 );
if( fillType != Box::Unfilled )
box->setBackground( fillType, QskRgbPalette::Indigo );
if( rounded )
box->setShape( 30, Qt::AbsoluteSize );
}
static void addColoredBorderRectangles2( QskLinearBox* parent, bool rounded, Box::FillType fillType )
{
Box* box = new Box( parent );
box->setBorderWidth( 20 );
box->setBorderGradients( Qt::red, Qt::green, Qt::blue, Qt::yellow );
if( fillType != Box::Unfilled )
box->setBackground( fillType, QskRgbPalette::Indigo );
if( rounded )
box->setShape( 30, Qt::AbsoluteSize );
}
static void addColoredBorderRectangles3( QskLinearBox* parent, bool rounded, Box::FillType fillType )
{
Box* box = new Box( parent );
box->setBorderWidth( 20 );
QskGradient gradient1( Qt::Vertical, { { 0.0, Qt::yellow },
{ 0.2, Qt::gray },
{ 0.6, Qt::magenta },
{ 1.0, Qt::green } } );
QskGradient gradient2( Qt::Vertical, { { 0.0, Qt::darkYellow },
{ 0.2, Qt::cyan },
{ 1.0, Qt::darkMagenta } } );
QskGradient gradient3( Qt::Vertical, { { 0.0, Qt::red },
{ 0.25, Qt::green },
{ 0.5, Qt::blue },
{ 0.75, Qt::magenta },
{ 1.0, Qt::cyan } } );
QskGradient gradient4( Qt::Vertical, { { 0.0, Qt::red },
{ 0.3, Qt::green },
{ 0.7, Qt::blue },
{ 1.0, Qt::cyan } } );
box->setBorderGradients( gradient3, gradient3, gradient3, gradient3 );
if( fillType != Box::Unfilled )
box->setBackground( fillType, QskRgbPalette::Indigo );
if( rounded )
box->setShape( 30, Qt::AbsoluteSize );
}
static void addColoredBorderRectangles4( QskLinearBox* parent, bool rounded, Box::FillType fillType )
{
Box* box = new Box( parent );
box->setBorderWidth( 20 );
QskGradient gradient( Qt::Vertical, Qt::magenta, Qt::cyan );
box->setBorderGradients( gradient, gradient, gradient, gradient );
if( fillType != Box::Unfilled )
box->setBackground( fillType, QskRgbPalette::Indigo );
if( rounded )
box->setShape( 30, Qt::AbsoluteSize );
}
static void addColoredBorderRectangles5( QskLinearBox* parent, bool rounded, Box::FillType fillType )
{
Box* box = new Box( parent );
box->setBorderWidth( 20 );
QskGradient gradient( Qt::Vertical, { { 0.0, Qt::black },
{ 0.3, Qt::white },
{ 0.7, Qt::white },
{ 1.0, Qt::black } } );
box->setBorderGradients( gradient, gradient, gradient, gradient );
if( fillType != Box::Unfilled )
box->setBackground( fillType, QskRgbPalette::Indigo );
if( rounded )
box->setShape( { 10, 20, 20, 40 } );
}
class TabView : public QskTabView
{
public:
@ -399,6 +494,45 @@ class TabView : public QskTabView
addTab( tab4 );
//setCurrentIndex( count() - 1 ); // setCurrentTab( tab4 ) -> TODO
#endif
auto* tab5 = new QskLinearBox( Qt::Horizontal, 5 );
addColoredBorderRectangles1( tab5, false, Box::Unfilled );
addColoredBorderRectangles2( tab5, false, Box::Unfilled );
addColoredBorderRectangles3( tab5, false, Box::Unfilled );
addColoredBorderRectangles4( tab5, false, Box::Unfilled );
addColoredBorderRectangles5( tab5, false, Box::Unfilled );
addColoredBorderRectangles1( tab5, true, Box::Unfilled );
addColoredBorderRectangles2( tab5, true, Box::Unfilled );
addColoredBorderRectangles3( tab5, true, Box::Unfilled );
addColoredBorderRectangles4( tab5, true, Box::Unfilled );
addColoredBorderRectangles5( tab5, true, Box::Unfilled );
addColoredBorderRectangles1( tab5, false, Box::Horizontal );
addColoredBorderRectangles2( tab5, false, Box::Horizontal );
addColoredBorderRectangles3( tab5, false, Box::Horizontal );
addColoredBorderRectangles4( tab5, false, Box::Horizontal );
addColoredBorderRectangles5( tab5, false, Box::Horizontal );
addColoredBorderRectangles1( tab5, true, Box::Horizontal );
addColoredBorderRectangles2( tab5, true, Box::Horizontal );
addColoredBorderRectangles3( tab5, true, Box::Horizontal );
addColoredBorderRectangles4( tab5, true, Box::Horizontal );
addColoredBorderRectangles5( tab5, true, Box::Horizontal );
addColoredBorderRectangles1( tab5, false, Box::Vertical );
addColoredBorderRectangles2( tab5, false, Box::Vertical );
addColoredBorderRectangles3( tab5, false, Box::Vertical );
addColoredBorderRectangles4( tab5, false, Box::Vertical );
addColoredBorderRectangles5( tab5, false, Box::Vertical );
addColoredBorderRectangles1( tab5, true, Box::Vertical );
addColoredBorderRectangles2( tab5, true, Box::Vertical );
addColoredBorderRectangles3( tab5, true, Box::Vertical );
addColoredBorderRectangles4( tab5, true, Box::Vertical );
addColoredBorderRectangles5( tab5, true, Box::Vertical );
addTab( tab5 );
}
private:

View File

@ -602,7 +602,7 @@ void Editor::setupTabButton()
QskBoxBorderColors borderColors( QskRgb::White );
setBoxBorderColors( aspect, borderColors );
borderColors.setColorsAt( edge, m_pal.accentColor );
borderColors.setGradientAt( edge, m_pal.accentColor );
for ( auto state : { Q::Checked, Q::Pressed, Q::Hovered } )
setBoxBorderColors( aspect | state, borderColors );
}
@ -750,8 +750,8 @@ void Editor::setupSubWindow()
setGradient( Q::Panel, m_pal.baseColor );
QskBoxBorderColors colors;
colors.setColorsAt( Qt::TopEdge | Qt::LeftEdge, m_pal.lighter125 );
colors.setColorsAt( Qt::RightEdge | Qt::BottomEdge, m_pal.darker200 );
colors.setGradientAt( Qt::TopEdge | Qt::LeftEdge, m_pal.lighter125 );
colors.setGradientAt( Qt::RightEdge | Qt::BottomEdge, m_pal.darker200 );
setBoxBorderColors( Q::Panel, colors );

View File

@ -198,23 +198,23 @@ void Editor::setButton( QskAspect aspect, PanelStyle style, qreal border )
{
case Raised:
{
borderColors.setColorsAt( Qt::TopEdge | Qt::LeftEdge, m_pal.lighter135 );
borderColors.setColorsAt( Qt::RightEdge | Qt::BottomEdge, m_pal.darker200 );
borderColors.setGradientAt( Qt::TopEdge | Qt::LeftEdge, m_pal.lighter135 );
borderColors.setGradientAt( Qt::RightEdge | Qt::BottomEdge, m_pal.darker200 );
gradient.setColors( m_pal.lighter125, m_pal.lighter110 );
break;
}
case Sunken:
{
borderColors.setColorsAt( Qt::TopEdge | Qt::LeftEdge, m_pal.darker200 );
borderColors.setColorsAt( Qt::RightEdge | Qt::BottomEdge, m_pal.lighter135 );
borderColors.setGradientAt( Qt::TopEdge | Qt::LeftEdge, m_pal.darker200 );
borderColors.setGradientAt( Qt::RightEdge | Qt::BottomEdge, m_pal.lighter135 );
gradient.setColors( m_pal.lighter110, m_pal.lighter125 );
break;
}
case Plain:
{
borderColors.setColors( m_pal.darker125 );
borderColors.setGradients( m_pal.darker125 );
gradient.setColor( m_pal.lighter125 );
break;
@ -225,7 +225,7 @@ void Editor::setButton( QskAspect aspect, PanelStyle style, qreal border )
QColor noColor( m_pal.theme );
noColor.setAlpha( 0 );
borderColors.setColors( noColor );
borderColors.setGradients( noColor );
gradient.setColor( noColor );
if ( style == NoPanel )
@ -859,8 +859,8 @@ void Editor::setupSubWindow()
setBoxShape( Q::Panel, radius, radius, 0, 0, Qt::AbsoluteSize );
QskBoxBorderColors borderColors;
borderColors.setColorsAt( Qt::TopEdge | Qt::LeftEdge, m_pal.lighter125 );
borderColors.setColorsAt( Qt::RightEdge | Qt::BottomEdge, m_pal.darker200 );
borderColors.setGradientAt( Qt::TopEdge | Qt::LeftEdge, m_pal.lighter125 );
borderColors.setGradientAt( Qt::RightEdge | Qt::BottomEdge, m_pal.darker200 );
setBoxBorderColors( Q::Panel, borderColors );
setGradient( Q::Panel, m_pal.lighter135 );

View File

@ -15,28 +15,26 @@ static void qskRegisterBoxBorderColors()
QMetaType::registerConverter< QColor, QskBoxBorderColors >(
[]( const QColor& color ) { return QskBoxBorderColors( color ); } );
QMetaType::registerConverter< QskGradient, QskBoxBorderColors >(
[]( const QskGradient& gradient ) { return QskBoxBorderColors( gradient ); } );
}
Q_CONSTRUCTOR_FUNCTION( qskRegisterBoxBorderColors )
static inline bool qskIsVisble( const QColor& c )
static inline void qskSetGradients( const QskGradient& gradient, QskGradient* gradients )
{
return c.isValid() && ( c.alpha() > 0 );
gradients[ 0 ] = gradients[ 1 ] = gradients[ 2 ] = gradients[ 3 ] = gradient;
}
static inline void qskSetColors( const QColor& c, QColor* colors )
static inline void qskSetGradients(
const QskGradient& left, const QskGradient& top,
const QskGradient& right, const QskGradient& bottom, QskGradient* gradients )
{
colors[ 0 ] = colors[ 1 ] = colors[ 2 ] = colors[ 3 ] = c.toRgb();
}
static inline void qskSetColors(
const QColor& left, const QColor& top,
const QColor& right, const QColor& bottom, QColor* colors )
{
colors[ Qsk::Left ] = left.toRgb();
colors[ Qsk::Top ] = top.toRgb();
colors[ Qsk::Right ] = right.toRgb();
colors[ Qsk::Bottom ] = bottom.toRgb();
gradients[ Qsk::Left ] = left;
gradients[ Qsk::Top ] = top;
gradients[ Qsk::Right ] = right;
gradients[ Qsk::Bottom ] = bottom;
}
QskBoxBorderColors::QskBoxBorderColors()
@ -44,15 +42,20 @@ QskBoxBorderColors::QskBoxBorderColors()
}
QskBoxBorderColors::QskBoxBorderColors(
const QColor& left, const QColor& top,
const QColor& right, const QColor& bottom )
const QskGradient& left, const QskGradient& top,
const QskGradient& right, const QskGradient& bottom )
{
qskSetColors( left, top, right, bottom, m_colors );
qskSetGradients( left, top, right, bottom, m_gradients );
}
QskBoxBorderColors::QskBoxBorderColors( const QColor& color )
{
qskSetColors( color, m_colors );
qskSetGradients( color, m_gradients );
}
QskBoxBorderColors::QskBoxBorderColors( const QskGradient& gradient )
{
qskSetGradients( gradient, m_gradients );
}
QskBoxBorderColors::~QskBoxBorderColors()
@ -61,88 +64,85 @@ QskBoxBorderColors::~QskBoxBorderColors()
bool QskBoxBorderColors::operator==( const QskBoxBorderColors& other ) const
{
return ( m_colors[ 0 ] == other.m_colors[ 0 ] ) &&
( m_colors[ 1 ] == other.m_colors[ 1 ] ) &&
( m_colors[ 2 ] == other.m_colors[ 2 ] ) &&
( m_colors[ 3 ] == other.m_colors[ 3 ] );
return ( m_gradients[ 0 ] == other.m_gradients[ 0 ] ) &&
( m_gradients[ 1 ] == other.m_gradients[ 1 ] ) &&
( m_gradients[ 2 ] == other.m_gradients[ 2 ] ) &&
( m_gradients[ 3 ] == other.m_gradients[ 3 ] );
}
void QskBoxBorderColors::setAlpha( int alpha )
{
for ( int i = 0; i < 4; i++ )
{
if ( m_colors[ i ].isValid() && m_colors[ i ].alpha() )
m_colors[ i ].setAlpha( alpha );
if ( m_gradients[ i ].isValid() )
m_gradients[ i ].setAlpha( alpha );
}
}
void QskBoxBorderColors::setColors( const QColor& color )
void QskBoxBorderColors::setGradients( const QskGradient& gradient )
{
qskSetColors( color, m_colors );
qskSetGradients( gradient, m_gradients );
}
void QskBoxBorderColors::setColors(
const QColor& left, const QColor& top,
const QColor& right, const QColor& bottom )
void QskBoxBorderColors::setGradients( const QskGradient& left, const QskGradient& top,
const QskGradient& right, const QskGradient& bottom )
{
qskSetColors( left, top, right, bottom, m_colors );
qskSetGradients( left, top, right, bottom, m_gradients );
}
void QskBoxBorderColors::setColor(
Qsk::Position position, const QColor& color )
void QskBoxBorderColors::setGradient( Qsk::Position position, const QskGradient& gradient )
{
m_colors[ position ] = color.toRgb();
m_gradients[ position ] = gradient;
}
void QskBoxBorderColors::setColorsAt( Qt::Edges edges, const QColor& color )
void QskBoxBorderColors::setGradientAt( Qt::Edges edges, const QskGradient& gradient )
{
const QColor c = color.toRgb();
if ( edges & Qt::TopEdge )
m_colors[ Qsk::Top ] = c;
m_gradients[ Qsk::Top ] = gradient;
if ( edges & Qt::LeftEdge )
m_colors[ Qsk::Left ] = c;
m_gradients[ Qsk::Left ] = gradient;
if ( edges & Qt::RightEdge )
m_colors[ Qsk::Right ] = c;
m_gradients[ Qsk::Right ] = gradient;
if ( edges & Qt::BottomEdge )
m_colors[ Qsk::Bottom ] = c;
m_gradients[ Qsk::Bottom ] = gradient;
}
QColor QskBoxBorderColors::colorAt( Qt::Edge edge ) const
const QskGradient& QskBoxBorderColors::gradientAt( Qt::Edge edge ) const
{
switch ( edge )
{
case Qt::TopEdge:
return m_colors[ Qsk::Top ];
return m_gradients[ Qsk::Top ];
case Qt::LeftEdge:
return m_colors[ Qsk::Left ];
return m_gradients[ Qsk::Left ];
case Qt::RightEdge:
return m_colors[ Qsk::Right ];
return m_gradients[ Qsk::Right ];
case Qt::BottomEdge:
return m_colors[ Qsk::Bottom ];
return m_gradients[ Qsk::Bottom ];
}
return QColor();
static QskGradient noGradient;
return noGradient;
}
bool QskBoxBorderColors::isVisible() const
{
if ( qskIsVisble( m_colors[ 0 ] ) )
if ( m_gradients[ 0 ].isVisible() )
return true;
if ( qskIsVisble( m_colors[ 1 ] ) )
if ( m_gradients[ 1 ].isVisible() )
return true;
if ( qskIsVisble( m_colors[ 2 ] ) )
if ( m_gradients[ 2 ].isVisible() )
return true;
if ( qskIsVisble( m_colors[ 3 ] ) )
if ( m_gradients[ 3 ].isVisible() )
return true;
return false;
@ -150,16 +150,19 @@ bool QskBoxBorderColors::isVisible() const
bool QskBoxBorderColors::isMonochrome() const
{
if ( m_colors[ 1 ] != m_colors[ 0 ] )
if ( m_gradients[ 1 ] != m_gradients[ 0 ] )
return false;
if ( m_colors[ 2 ] != m_colors[ 1 ] )
if ( m_gradients[ 2 ] != m_gradients[ 1 ] )
return false;
if ( m_colors[ 3 ] != m_colors[ 2 ] )
if ( m_gradients[ 3 ] != m_gradients[ 2 ] )
return false;
return true;
return m_gradients[ 0 ].isMonochrome()
&& m_gradients[ 1 ].isMonochrome()
&& m_gradients[ 2 ].isMonochrome()
&& m_gradients[ 3 ].isMonochrome();
}
QskBoxBorderColors QskBoxBorderColors::interpolated(
@ -169,8 +172,8 @@ QskBoxBorderColors QskBoxBorderColors::interpolated(
for ( size_t i = 0; i < 4; i++ )
{
colors.m_colors[ i ] = QskRgb::interpolated(
m_colors[ i ], to.m_colors[ i ], ratio );
colors.m_gradients[ i ] = colors.m_gradients[ i ].interpolated(
to.m_gradients[ i ], ratio );
}
return colors;
@ -184,30 +187,18 @@ QVariant QskBoxBorderColors::interpolate(
uint QskBoxBorderColors::hash( uint seed ) const
{
const QRgb rgb[] =
{
m_colors[ 0 ].rgba(),
m_colors[ 1 ].rgba(),
m_colors[ 2 ].rgba(),
m_colors[ 3 ].rgba(),
};
uint h = m_gradients[ 0 ].hash( seed );
h = m_gradients[ 1 ].hash( h );
h = m_gradients[ 2 ].hash( h );
h = m_gradients[ 3 ].hash( h );
return qHashBits( rgb, sizeof( rgb ), seed );
return h;
}
#ifndef QT_NO_DEBUG_STREAM
#include <qdebug.h>
static inline void qskDebugColor( QDebug debug, const QColor& c )
{
debug << '('
<< c.red() << ','
<< c.green() << ','
<< c.blue() << ','
<< c.alpha() << ')';
}
QDebug operator<<( QDebug debug, const QskBoxBorderColors& colors )
{
QDebugStateSaver saver( debug );
@ -215,17 +206,13 @@ QDebug operator<<( QDebug debug, const QskBoxBorderColors& colors )
debug << "BoxBorderColors" << '(';
debug << " L";
qskDebugColor( debug, colors.color( Qsk::Left ) );
debug << " L" << colors.gradient( Qsk::Left );
debug << ", T";
qskDebugColor( debug, colors.color( Qsk::Top ) );
debug << ", T" << colors.gradient( Qsk::Top );
debug << ", R";
qskDebugColor( debug, colors.color( Qsk::Right ) );
debug << ", R" << colors.gradient( Qsk::Right );
debug << ", B";
qskDebugColor( debug, colors.color( Qsk::Bottom ) );
debug << ", B" << colors.gradient( Qsk::Bottom );
debug << " )";

View File

@ -6,6 +6,7 @@
#ifndef QSK_BOX_BORDER_COLORS_H
#define QSK_BOX_BORDER_COLORS_H
#include "QskGradient.h"
#include "QskNamespace.h"
#include <qcolor.h>
@ -18,12 +19,13 @@ class QSK_EXPORT QskBoxBorderColors
public:
QskBoxBorderColors();
QskBoxBorderColors( const QColor& left, const QColor& top,
const QColor& right, const QColor& bottom );
QskBoxBorderColors( const QskGradient& left, const QskGradient& top,
const QskGradient& right, const QskGradient& bottom );
QskBoxBorderColors( Qt::GlobalColor );
QskBoxBorderColors( QRgb );
QskBoxBorderColors( const QColor& );
QskBoxBorderColors( const QskGradient& );
~QskBoxBorderColors();
@ -32,17 +34,15 @@ class QSK_EXPORT QskBoxBorderColors
void setAlpha( int alpha );
void setColors( const QColor& );
void setColors( const QColor& left, const QColor& top,
const QColor& right, const QColor& bottom );
void setGradients( const QskGradient& );
void setGradients( const QskGradient& left, const QskGradient& top,
const QskGradient& right, const QskGradient& bottom );
void setColor( Qsk::Position, const QColor& );
QColor color( Qsk::Position ) const;
void setGradient( Qsk::Position, const QskGradient& );
QskGradient gradient( Qsk::Position ) const;
void setColorsAt( Qt::Edges, const QColor& );
QColor colorAt( Qt::Edge ) const;
QRgb rgb( Qsk::Position ) const;
void setGradientAt( Qt::Edges, const QskGradient& );
const QskGradient& gradientAt( Qt::Edge ) const;
QskBoxBorderColors interpolated( const QskBoxBorderColors&, qreal value ) const;
@ -55,8 +55,7 @@ class QSK_EXPORT QskBoxBorderColors
bool isVisible() const;
private:
// should be stored as QRgb
QColor m_colors[ 4 ];
QskGradient m_gradients[ 4 ];
};
inline QskBoxBorderColors::QskBoxBorderColors( Qt::GlobalColor color )
@ -74,14 +73,9 @@ inline bool QskBoxBorderColors::operator!=( const QskBoxBorderColors& other ) co
return !( *this == other );
}
inline QColor QskBoxBorderColors::color( Qsk::Position position ) const
inline QskGradient QskBoxBorderColors::gradient( Qsk::Position position ) const
{
return m_colors[ position ];
}
inline QRgb QskBoxBorderColors::rgb( Qsk::Position position ) const
{
return m_colors[ position ].rgba();
return m_gradients[ position ];
}
#ifndef QT_NO_DEBUG_STREAM

View File

@ -471,9 +471,9 @@ void QskSkinHintTableEditor::setBoxBorderColors(
setColorHint( aspectBorder( aspect ), borderColors, combination );
}
void QskSkinHintTableEditor::setBoxBorderColors( QskAspect aspect,
const QColor& left, const QColor& top, const QColor& right, const QColor& bottom,
QskStateCombination combination )
void QskSkinHintTableEditor::setBoxBorderColors(QskAspect aspect,
const QskGradient& left, const QskGradient& top, const QskGradient& right,
const QskGradient& bottom, QskStateCombination combination )
{
setColorHint( aspectBorder( aspect ),
QskBoxBorderColors( left, top, right, bottom ),

View File

@ -227,7 +227,8 @@ class QSK_EXPORT QskSkinHintTableEditor
const QskBoxBorderColors&, QskStateCombination = QskStateCombination() );
void setBoxBorderColors( QskAspect,
const QColor& left, const QColor& top, const QColor& right, const QColor& bottom,
const QskGradient& left, const QskGradient& top,
const QskGradient& right, const QskGradient& bottom,
QskStateCombination = QskStateCombination() );
void removeBoxBorderColors( QskAspect, QskStateCombination = QskStateCombination() );

View File

@ -117,7 +117,8 @@ void QskBoxNode::setBoxData( const QRectF& rect,
{
if ( isFillMonochrome && isBorderMonochrome )
{
if ( borderColors.color( Qsk::Left ) == fillGradient.startColor() )
if ( borderColors.gradient( Qsk::Left ).startColor()
== fillGradient.startColor() )
{
// we can draw border and background in one
hasBorder = false;
@ -171,7 +172,7 @@ void QskBoxNode::setBoxData( const QRectF& rect,
}
else
{
flatMaterial->setColor( borderColors.color( Qsk::Left ).rgba() );
flatMaterial->setColor( borderColors.gradient( Qsk::Left ).startColor().rgba() );
renderer.renderBorder( m_rect, shape, borderMetrics, *geometry() );
}
}

View File

@ -97,6 +97,26 @@ namespace
int m_stepCount;
bool m_inverted;
};
int additionalGradientStops( const QskGradient& gradient )
{
return qMax( 0, gradient.stops().count() - 2 );
}
static inline QRgb qskRgbGradientStart( const QskGradient& gradient )
{
return gradient.startColor().rgba();
}
static inline QRgb qskRgbGradientEnd( const QskGradient& gradient )
{
return gradient.endColor().rgba();
}
static inline QRgb qskRgbBorder( const QskBoxBorderColors& borderColors )
{
return qskRgbGradientStart( borderColors.gradient( Qsk::Left ) );
}
}
namespace
@ -488,6 +508,7 @@ namespace
{
public:
static inline constexpr Color colorAt( int ) { return Color(); }
inline QskGradient gradient() const { return QskGradient(); }
};
class BorderMapSolid
@ -499,6 +520,7 @@ namespace
}
inline Color colorAt( int ) const { return m_color; }
inline QskGradient gradient() const { return QskGradient(); }
const Color m_color;
};
@ -506,10 +528,11 @@ namespace
class BorderMapGradient
{
public:
inline BorderMapGradient( int stepCount, QRgb rgb1, QRgb rgb2 )
inline BorderMapGradient( int stepCount, QRgb rgb1, QRgb rgb2, const QskGradient& gradient )
: m_stepCount( stepCount )
, m_color1( rgb1 )
, m_color2( rgb2 )
, m_gradient( gradient )
{
}
@ -518,9 +541,15 @@ namespace
return m_color1.interpolatedTo( m_color2, step / m_stepCount );
}
inline QskGradient gradient() const
{
return m_gradient;
}
private:
const qreal m_stepCount;
const Color m_color1, m_color2;
const QskGradient m_gradient;
};
template< class Line, class BorderValues >
@ -532,6 +561,27 @@ namespace
{
}
void addAdditionalLines( float x11, float y11, float x12, float y12, // start line
float x21,float y21, float x22, float y22, // end line
const QskGradient& gradient, Line* lines )
{
int additionalStopCount = additionalGradientStops( gradient );
auto s = gradient.stops();
for( int i = 1; i <= additionalStopCount; ++i )
{
auto p = ( 1 - s.at( i ).position() );
float xStart = x11 + p * ( x21 - x11 ),
yStart = y11 + p * ( y21 - y11 ),
xEnd = x12 + p * ( x22 - x12 ),
yEnd = y12 + p * ( y22 - y12 );
lines[ additionalStopCount - i + 1 ].setLine( xStart, yStart,
xEnd, yEnd, s.at( i ).color() );
}
}
template< class BorderMap, class FillMap >
inline void createLines( Qt::Orientation orientation, Line* borderLines,
const BorderMap& borderMapTL, const BorderMap& borderMapTR,
@ -555,9 +605,12 @@ namespace
if ( borderLines )
{
linesBR = borderLines;
linesTR = linesBR + numCornerLines;
linesTL = linesTR + numCornerLines;
linesBL = linesTL + numCornerLines;
linesTR = linesBR + numCornerLines
+ additionalGradientStops( borderMapBR.gradient() );
linesTL = linesTR + numCornerLines
+ additionalGradientStops( borderMapTR.gradient() );
linesBL = linesTL + numCornerLines
+ additionalGradientStops( borderMapTL.gradient() );
}
if ( fillLines )
@ -571,9 +624,12 @@ namespace
if ( borderLines )
{
linesTR = borderLines + 1;
linesTL = linesTR + numCornerLines;
linesBL = linesTL + numCornerLines;
linesBR = linesBL + numCornerLines;
linesTL = linesTR + numCornerLines
+ additionalGradientStops( borderMapTR.gradient() );
linesBL = linesTL + numCornerLines
+ additionalGradientStops( borderMapTL.gradient() );
linesBR = linesBL + numCornerLines
+ additionalGradientStops( borderMapBL.gradient() );
}
if ( fillLines )
@ -641,6 +697,83 @@ namespace
c[ corner ].centerY + v.dy2( corner ),
borderMapBR.colorAt( j ) );
}
// at the beginning and end of the loop we can add
// additional lines for border gradients:
if( j == 0 )
{
if( additionalGradientStops( borderMapTR.gradient() ) > 0 )
{
float x1TR = c[ TopRight ].centerX + v.dx1( TopRight ),
y1TR = c[ TopRight ].centerY - v.dy1( TopRight ),
x2TR = c[ TopRight ].centerX + v.dx2( TopRight ),
y2TR = c[ TopRight ].centerY - v.dy2( TopRight ),
x1TL = c[ TopLeft ].centerX - v.dx1( TopLeft ),
y1TL = c[ TopLeft ].centerY - v.dy1( TopLeft ),
x2TL = c[ TopLeft ].centerX - v.dx2( TopLeft ),
y2TL = c[ TopLeft ].centerY - v.dy2( TopLeft );
addAdditionalLines( x1TR, y1TR, x2TR, y2TR,
x1TL, y1TL, x2TL, y2TL,
borderMapTR.gradient(), linesTR + k );
}
if( additionalGradientStops( borderMapBL.gradient() ) > 0 )
{
float x1BL = c[ BottomLeft ].centerX - v.dx1( BottomLeft ),
y1BL = c[ BottomLeft ].centerY + v.dy1( BottomLeft ),
x2BL = c[ BottomLeft ].centerX - v.dx2( BottomLeft ),
y2BL = c[ BottomLeft ].centerY + v.dy2( BottomLeft ),
x1BR = c[ BottomRight ].centerX + v.dx1( BottomRight ),
y1BR = c[ BottomRight ].centerY + v.dy1( BottomRight ),
x2BR = c[ BottomRight ].centerX + v.dx2( BottomRight ),
y2BR = c[ BottomRight ].centerY + v.dy2( BottomRight );
addAdditionalLines( x1BL, y1BL, x2BL, y2BL,
x1BR, y1BR, x2BR, y2BR,
borderMapBL.gradient(), linesBL + k );
}
}
if( j == numCornerLines - 1 )
{
if( additionalGradientStops( borderMapTL.gradient() ) > 0 )
{
float x1TL = c[ TopLeft ].centerX - v.dx1( TopLeft ),
y1TL = c[ TopLeft ].centerY - v.dy1( TopLeft ),
x2TL = c[ TopLeft ].centerX - v.dx2( TopLeft ),
y2TL = c[ TopLeft ].centerY - v.dy2( TopLeft ),
x1BL = c[ BottomLeft ].centerX - v.dx1( BottomLeft ),
y1BL = c[ BottomLeft ].centerY + v.dy1( BottomLeft ),
x2BL = c[ BottomLeft ].centerX - v.dx2( BottomLeft ),
y2BL = c[ BottomLeft ].centerY + v.dy2( BottomLeft );
addAdditionalLines( x1TL, y1TL, x2TL, y2TL,
x1BL, y1BL, x2BL, y2BL,
borderMapTL.gradient(), linesTL + j );
}
if( additionalGradientStops( borderMapBR.gradient() ) > 0 )
{
float x1BR = c[ BottomRight ].centerX + v.dx1( BottomRight ),
y1BR = c[ BottomRight ].centerY + v.dy1( BottomRight ),
x2BR = c[ BottomRight ].centerX + v.dx2( BottomRight ),
y2BR = c[ BottomRight ].centerY + v.dy2( BottomRight ),
x1TR = c[ TopRight ].centerX + v.dx1( TopRight ),
y1TR = c[ TopRight ].centerY - v.dy1( TopRight ),
x2TR = c[ TopRight ].centerX + v.dx2( TopRight ),
y2TR = c[ TopRight ].centerY - v.dy2( TopRight );
addAdditionalLines( x1BR, y1BR, x2BR, y2BR,
x1TR, y1TR, x2TR, y2TR,
borderMapBR.gradient(), linesBR + j );
}
}
}
if ( fillLines )
@ -689,7 +822,12 @@ namespace
#if 1
if ( borderLines )
{
const int k = 4 * numCornerLines;
const int additionalStops =
additionalGradientStops( borderMapBR.gradient() )
+ additionalGradientStops( borderMapTR.gradient() )
+ additionalGradientStops( borderMapTL.gradient() )
+ additionalGradientStops( borderMapBL.gradient() );
const int k = 4 * numCornerLines + additionalStops;
if ( orientation == Qt::Vertical )
borderLines[ k ] = borderLines[ 0 ];
@ -859,17 +997,24 @@ static inline void qskRenderBorder( const QskBoxRenderer::Metrics& metrics,
if ( colors.isMonochrome() )
{
qskRenderBorderLines( metrics, orientation, line, BorderMapSolid( c.rgb( Qsk::Left ) ) );
qskRenderBorderLines( metrics, orientation, line, BorderMapSolid( qskRgbBorder( c ) ) );
}
else
{
const int stepCount = metrics.corner[ 0 ].stepCount;
auto left = c.gradient( Qsk::Left ), top = c.gradient( Qsk::Top ),
right = c.gradient( Qsk::Right ), bottom = c.gradient( Qsk::Bottom );
qskRenderBorderLines( metrics, orientation, line,
BorderMapGradient( stepCount, c.rgb( Qsk::Top ), c.rgb( Qsk::Left ) ),
BorderMapGradient( stepCount, c.rgb( Qsk::Right ), c.rgb( Qsk::Top ) ),
BorderMapGradient( stepCount, c.rgb( Qsk::Left ), c.rgb( Qsk::Bottom ) ),
BorderMapGradient( stepCount, c.rgb( Qsk::Bottom ), c.rgb( Qsk::Right ) ) );
BorderMapGradient( stepCount, qskRgbGradientStart( top ),
qskRgbGradientEnd( left ), left ),
BorderMapGradient( stepCount, qskRgbGradientStart( right ),
qskRgbGradientEnd( top ), top ),
BorderMapGradient( stepCount, qskRgbGradientStart( left ),
qskRgbGradientEnd( bottom ), bottom ),
BorderMapGradient( stepCount, qskRgbGradientStart( bottom ),
qskRgbGradientEnd( right ), right ) );
}
}
@ -899,7 +1044,7 @@ static inline void qskRenderBoxRandom(
if ( bc.isMonochrome() )
{
const BorderMapSolid borderMap( bc.rgb( Qsk::Left ) );
const BorderMapSolid borderMap( qskRgbBorder( bc.gradient( Qsk::Left ) ) );
if ( gradient.isMonochrome() )
{
@ -918,10 +1063,17 @@ static inline void qskRenderBoxRandom(
{
const int n = metrics.corner[ 0 ].stepCount;
const BorderMapGradient tl( n, bc.rgb( Qsk::Top ), bc.rgb( Qsk::Left ) );
const BorderMapGradient tr( n, bc.rgb( Qsk::Right ), bc.rgb( Qsk::Top ) );
const BorderMapGradient bl( n, bc.rgb( Qsk::Left ), bc.rgb( Qsk::Bottom ) );
const BorderMapGradient br( n, bc.rgb( Qsk::Bottom ), bc.rgb( Qsk::Right ) );
auto left = bc.gradient( Qsk::Left ), top = bc.gradient( Qsk::Top ),
right = bc.gradient( Qsk::Right ), bottom = bc.gradient( Qsk::Bottom );
const BorderMapGradient tl( n, qskRgbGradientStart( top.startColor() ),
qskRgbGradientEnd( left.endColor() ), left );
const BorderMapGradient tr( n, qskRgbGradientStart( right ),
qskRgbGradientEnd( top ), top );
const BorderMapGradient bl( n, qskRgbGradientStart( left ),
qskRgbGradientEnd( bottom ), bottom );
const BorderMapGradient br( n, qskRgbGradientStart( bottom ),
qskRgbGradientEnd( right ), right );
if ( gradient.isMonochrome() )
{
@ -1207,9 +1359,20 @@ void QskBoxRenderer::renderRectellipse( const QRectF& rect,
const int stepCount = metrics.corner[ 0 ].stepCount;
int borderLineCount = 0;
if ( borderColors.isVisible() && metrics.innerQuad != metrics.outerQuad )
{
borderLineCount = 4 * ( stepCount + 1 ) + 1;
const int additionalLines =
additionalGradientStops( borderColors.gradient( Qsk::Left ) )
+ additionalGradientStops( borderColors.gradient( Qsk::Top ) )
+ additionalGradientStops( borderColors.gradient( Qsk::Right ) )
+ additionalGradientStops( borderColors.gradient( Qsk::Bottom ) );
borderLineCount += additionalLines;
}
int lineCount = borderLineCount + fillLineCount;
bool extraLine = false;

View File

@ -422,28 +422,63 @@ static inline void qskCreateBorder(
const QskBoxRenderer::Quad& out, const QskBoxRenderer::Quad& in,
const QskBoxBorderColors& colors, Line* line )
{
const Color colorLeft = colors.rgb( Qsk::Left );
const Color colorRight = colors.rgb( Qsk::Right );
const Color colorTop = colors.rgb( Qsk::Top );
const Color colorBottom = colors.rgb( Qsk::Bottom );
const QskGradient gradientLeft = colors.gradient( Qsk::Left );
const QskGradient gradientRight = colors.gradient( Qsk::Right );
const QskGradient gradientTop = colors.gradient( Qsk::Top );
const QskGradient gradientBottom = colors.gradient( Qsk::Bottom );
( line++ )->setLine( in.right, in.bottom, out.right, out.bottom, colorBottom );
( line++ )->setLine( in.left, in.bottom, out.left, out.bottom, colorBottom );
// qdebug
if ( colorLeft != colorBottom )
( line++ )->setLine( in.left, in.bottom, out.left, out.bottom, colorLeft );
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;
( line++ )->setLine( in.left, in.top, out.left, out.top, colorLeft );
for( const auto& stop : gradientBottom.stops() )
{
const Color c( stop.color() );
const qreal x1 = in.right - stop.position() * dx1;
const qreal x2 = out.right - stop.position() * dx2;
const qreal y1 = in.bottom;
const qreal y2 = out.bottom;
if ( colorTop != colorLeft )
( line++ )->setLine( in.left, in.top, out.left, out.top, colorTop );
( line++ )->setLine( x1, y1, x2, y2, c );
}
( line++ )->setLine( in.right, in.top, out.right, out.top, colorTop );
for( const auto& stop : gradientLeft.stops() )
{
const Color c( stop.color() );
const qreal x1 = in.left;
const qreal x2 = out.left;
const qreal y1 = in.bottom + stop.position() * dy1;
const qreal y2 = out.bottom + stop.position() * dy2;
if ( colorRight != colorTop )
( line++ )->setLine( in.right, in.top, out.right, out.top, colorRight );
( line++ )->setLine( x1, y1, x2, y2, c );
}
( line++ )->setLine( in.right, in.bottom, out.right, out.bottom, colorRight );
for( const auto& stop : gradientTop.stops() )
{
const Color c( stop.color() );
const qreal x1 = in.left + stop.position() * dx1;
const qreal x2 = out.left + stop.position() * dx2;
const qreal y1 = in.top;
const qreal y2 = out.top;
( line++ )->setLine( x1, y1, x2, y2, c );
}
for( const auto& stop : gradientRight.stops() )
{
const Color c( stop.color() );
const qreal x1 = in.right;
const qreal x2 = out.right;
// ( 1 - stop.position() ) because we want to make the gradients go
// around the border clock-wise:
const qreal y1 = in.bottom + ( 1 - stop.position() ) * dy1;
const qreal y2 = out.bottom + ( 1 - stop.position() ) * dy2;
( line++ )->setLine( x1, y1, x2, y2, c );
}
}
void QskBoxRenderer::renderRectBorder(
@ -533,14 +568,15 @@ void QskBoxRenderer::renderRect(
// we might need extra lines to separate colors
// at the non closing corners
if ( bc.color( Qsk::Left ) != bc.color( Qsk::Bottom ) )
borderLineCount++;
// ### As an optimization we could check orientation and colors
// to test whether colors are the same
const int additionalLines = -1
+ bc.gradient( Qsk::Left ).stops().count() - 1
+ bc.gradient( Qsk::Top ).stops().count() - 1
+ bc.gradient( Qsk::Right ).stops().count() - 1
+ bc.gradient( Qsk::Bottom ).stops().count() - 1;
if ( bc.color( Qsk::Top ) != bc.color( Qsk::Left ) )
borderLineCount++;
if ( bc.color( Qsk::Right ) != bc.color( Qsk::Top ) )
borderLineCount++;
borderLineCount += qMax( additionalLines, 0 );
}
}
}
@ -587,7 +623,7 @@ void QskBoxRenderer::renderRect(
auto fillLines = line + fillLineCount;
if ( bc.isMonochrome() )
qskCreateBorderMonochrome( rect, in, bc.rgb( Qsk::Left ), fillLines );
qskCreateBorderMonochrome( rect, in, bc.gradient( Qsk::Left ).startColor().rgba(), fillLines );
else
qskCreateBorder( rect, in, bc, fillLines );
}