diff --git a/examples/boxes/Box.cpp b/examples/boxes/Box.cpp index 0802642d..a1de2035 100644 --- a/examples/boxes/Box.cpp +++ b/examples/boxes/Box.cpp @@ -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 ) diff --git a/examples/boxes/Box.h b/examples/boxes/Box.h index caf1f405..4ee0bd06 100644 --- a/examples/boxes/Box.h +++ b/examples/boxes/Box.h @@ -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 ); diff --git a/examples/boxes/main.cpp b/examples/boxes/main.cpp index 7b057dc7..bfe8678d 100644 --- a/examples/boxes/main.cpp +++ b/examples/boxes/main.cpp @@ -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: diff --git a/skins/material/QskMaterialSkin.cpp b/skins/material/QskMaterialSkin.cpp index c5948549..2bf3432d 100644 --- a/skins/material/QskMaterialSkin.cpp +++ b/skins/material/QskMaterialSkin.cpp @@ -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 ); diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 5fb16fe9..377141c7 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -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 ); diff --git a/src/common/QskBoxBorderColors.cpp b/src/common/QskBoxBorderColors.cpp index c0a92f6e..1dc4f5b3 100644 --- a/src/common/QskBoxBorderColors.cpp +++ b/src/common/QskBoxBorderColors.cpp @@ -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 -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 << " )"; diff --git a/src/common/QskBoxBorderColors.h b/src/common/QskBoxBorderColors.h index 275b9538..daec2b68 100644 --- a/src/common/QskBoxBorderColors.h +++ b/src/common/QskBoxBorderColors.h @@ -6,6 +6,7 @@ #ifndef QSK_BOX_BORDER_COLORS_H #define QSK_BOX_BORDER_COLORS_H +#include "QskGradient.h" #include "QskNamespace.h" #include @@ -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 diff --git a/src/controls/QskSkinHintTableEditor.cpp b/src/controls/QskSkinHintTableEditor.cpp index e310ffdf..ea88434a 100644 --- a/src/controls/QskSkinHintTableEditor.cpp +++ b/src/controls/QskSkinHintTableEditor.cpp @@ -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 ), diff --git a/src/controls/QskSkinHintTableEditor.h b/src/controls/QskSkinHintTableEditor.h index 42739028..a6845d35 100644 --- a/src/controls/QskSkinHintTableEditor.h +++ b/src/controls/QskSkinHintTableEditor.h @@ -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() ); diff --git a/src/nodes/QskBoxNode.cpp b/src/nodes/QskBoxNode.cpp index cd7d9052..586157ba 100644 --- a/src/nodes/QskBoxNode.cpp +++ b/src/nodes/QskBoxNode.cpp @@ -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() ); } } diff --git a/src/nodes/QskBoxRendererEllipse.cpp b/src/nodes/QskBoxRendererEllipse.cpp index 68c5882a..a9ec43fc 100644 --- a/src/nodes/QskBoxRendererEllipse.cpp +++ b/src/nodes/QskBoxRendererEllipse.cpp @@ -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; diff --git a/src/nodes/QskBoxRendererRect.cpp b/src/nodes/QskBoxRendererRect.cpp index acbcab62..339957f2 100644 --- a/src/nodes/QskBoxRendererRect.cpp +++ b/src/nodes/QskBoxRendererRect.cpp @@ -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 ); }