diff --git a/examples/boxes/Box.cpp b/examples/boxes/Box.cpp index 1849edf1..ca1b2c5f 100644 --- a/examples/boxes/Box.cpp +++ b/examples/boxes/Box.cpp @@ -10,6 +10,21 @@ #include #include #include +#include + +static inline void setStartStop( Box::FillType type, QskLinearGradient& gradient ) +{ + qreal x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0; + + if ( type != Box::Horizontal ) + y2 = 1.0; + + if ( type != Box::Vertical ) + x2 = 1.0; + + gradient.setStart( x1, y1 ); + gradient.setStop( x2, y2 ); +} Box::Box( QQuickItem* parentItem ) : QskBox( parentItem ) @@ -20,67 +35,88 @@ Box::Box( QQuickItem* parentItem ) setBoxShapeHint( QskBox::Panel, QskBoxShapeMetrics() ); setBoxBorderMetricsHint( QskBox::Panel, QskBoxBorderMetrics() ); setBoxBorderColorsHint( QskBox::Panel, QskBoxBorderColors() ); - setGradientHint( QskBox::Panel, QskGradient() ); + setPanelGradient( QskGradient() ); } -void Box::setBackground( FillType type, QGradient::Preset preset, bool inverted ) +void Box::setWebGradient( FillType type, QGradient::Preset preset, bool inverted ) { if ( type == Unfilled ) { - setGradient( QskGradient() ); + setPanelGradient( QskGradient() ); return; } - QskGradient gradient( preset ); + QskLinearGradient gradient( preset ); if ( type == Solid ) { const auto color = QskRgb::interpolated( gradient.startColor(), gradient.endColor(), 0.5 ); - setGradient( QskGradient( color ) ); + gradient.setStops( color ); } - else - { - const auto orientation = - static_cast< QskGradient::Orientation >( type - 2 ); - gradient.setOrientation( orientation ); + setStartStop( type, gradient ); - if ( inverted ) - gradient.reverse(); + if ( inverted ) + gradient.reverse(); - setGradient( gradient ); - } + setPanelGradient( gradient ); } -void Box::setBackground( FillType type, const QRgb base, bool inverted ) +void Box::setTonalGradient( FillType type, const QRgb base, bool inverted ) { if ( type == Unfilled ) { - setGradient( QskGradient() ); + setPanelGradient( QskGradient() ); return; } - const QskHctColor htcColor( base ); + QskLinearGradient gradient; + const QskHctColor htcColor( base ); if ( type == Solid ) { - setGradient( htcColor.toned( 50 ).rgb() ); + gradient.setStops( htcColor.toned( 50 ).rgb() ); } - else + else if ( type != Unfilled ) { - const auto dark = htcColor.toned( 40 ).rgb(); - const auto light = htcColor.toned( 70 ).rgb(); - - const auto orientation = - static_cast< QskGradient::Orientation >( type - 2 ); - - if ( inverted ) - setGradient( orientation, dark, light ); - else - setGradient( orientation, light, dark ); + gradient.setStops( htcColor.toned( 70 ).rgb(), + htcColor.toned( 40 ).rgb() ); } + + setStartStop( type, gradient ); + + if ( inverted ) + gradient.reverse(); + + setPanelGradient( gradient ); +} + +void Box::setTonalPalette( FillType type, const QRgb base ) +{ + if ( type == Unfilled || type == Solid ) + { + setTonalGradient( type, base ); + return; + } + + QskLinearGradient gradient; + setStartStop( type, gradient ); + + { + const QskHctColor hctColor( base ); + + QVector< QRgb > colors; + colors.reserve( 10 ); + + for ( int i = 0; i < 10; i++ ) + colors += hctColor.toned( 90 - i * 7 ).rgb(); + + gradient.setStops( qskBuildGradientStops( colors, true ) ); + } + + setPanelGradient( gradient ); } void Box::setBorder( BorderType type, const QRgb base ) @@ -165,26 +201,30 @@ void Box::setBorderWidth( int width ) void Box::setGradient( QRgb rgb ) { - setGradient( QskGradient( QColor::fromRgba( rgb ) ) ); + setGradient( QColor::fromRgba( rgb ) ); } void Box::setGradient( Qt::GlobalColor color ) { - setGradient( QskGradient( color ) ); + setGradient( QColor( color ) ); } void Box::setGradient( const QColor& color ) { - setGradient( QskGradient( color ) ); + setPanelGradient( QskLinearGradient( color ) ); } -void Box::setGradient( QskGradient::Orientation orientation, +void Box::setGradient( FillType fillType, const QColor& color1, const QColor& color2 ) { - setGradient( QskGradient( orientation, color1, color2 ) ); + QskGradientStops stops; + stops += QskGradientStop( 0.0, color1 ); + stops += QskGradientStop( 1.0, color2 ); + + setGradient( fillType, stops ); } -void Box::setGradient( QskGradient::Orientation orientation, +void Box::setGradient( FillType fillType, const QColor& color1, const QColor& color2, const QColor& color3 ) { QskGradientStops stops; @@ -192,24 +232,18 @@ void Box::setGradient( QskGradient::Orientation orientation, stops += QskGradientStop( 0.5, color2 ); stops += QskGradientStop( 1.0, color3 ); - setGradient( QskGradient( orientation, stops ) ); + setGradient( fillType, stops ); } -void Box::setGradient( const QskGradient& gradient ) +void Box::setGradient( FillType fillType, const QskGradientStops& stops ) +{ + QskLinearGradient gradient( stops ); + setStartStop( fillType, gradient ); + + setPanelGradient( gradient ); +} + +void Box::setPanelGradient( const QskGradient& gradient ) { setGradientHint( QskBox::Panel, gradient ); } - -void Box::setGradient( - const QskGradient::Orientation orientation, const QRgb base ) -{ - const QskHctColor hctColor( base ); - - QVector< QRgb > colors; - colors.reserve( 10 ); - - for ( int i = 0; i < 10; i++ ) - colors += hctColor.toned( 90 - i * 7 ).rgb(); - - setGradient( QskGradient( orientation, qskBuildGradientStops( colors, true ) ) ); -} diff --git a/examples/boxes/Box.h b/examples/boxes/Box.h index de2c4205..d45d9d12 100644 --- a/examples/boxes/Box.h +++ b/examples/boxes/Box.h @@ -31,9 +31,6 @@ class Box : public QskBox Box( QQuickItem* parentItem = nullptr ); - void setBackground( FillType, QRgb, bool inverted = false ); - void setBackground( FillType, QGradient::Preset, bool inverted = false ); - void setBorder( BorderType type, QRgb ); void setShape( const QskBoxShapeMetrics& ); @@ -51,11 +48,15 @@ class Box : public QskBox void setGradient( Qt::GlobalColor ); void setGradient( const QColor& ); - void setGradient( QskGradient::Orientation, const QColor&, const QColor& ); + void setGradient( FillType, const QColor&, const QColor& ); + void setGradient( FillType, const QColor&, const QColor&, const QColor& ); + void setGradient( FillType, const QskGradientStops& ); - void setGradient( QskGradient::Orientation, - const QColor&, const QColor&, const QColor& ); + void setTonalGradient( FillType, QRgb, bool inverted = false ); + void setWebGradient( FillType, QGradient::Preset, bool inverted = false ); - void setGradient( const QskGradient& ); - void setGradient( const QskGradient::Orientation, QRgb ); + void setTonalPalette( FillType, QRgb ); + + private: + void setPanelGradient( const QskGradient& ); }; diff --git a/examples/boxes/main.cpp b/examples/boxes/main.cpp index 8641e48d..21af3968 100644 --- a/examples/boxes/main.cpp +++ b/examples/boxes/main.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -75,7 +74,7 @@ static void addTestRectangle( QskLinearBox* parent ) shape.setRadius( Qt::TopRightCorner, 70 ); box->setShape( shape ); - box->setGradient( QskGradient::Diagonal, QskRgb::DodgerBlue ); + box->setTonalPalette( Box::Diagonal, QskRgb::DodgerBlue ); } static void addRectangles1( QskLinearBox* parent ) @@ -84,7 +83,7 @@ static void addRectangles1( QskLinearBox* parent ) Box::Horizontal, Box::Vertical, Box::Diagonal } ) { auto* rectangle = new MyRectangle( parent ); - rectangle->setBackground( type, QskRgb::Teal ); + rectangle->setTonalGradient( type, QskRgb::Teal ); } } @@ -95,7 +94,7 @@ static void addRectangles2( QskLinearBox* parent ) { auto* rectangle = new MyRectangle( parent ); rectangle->setBorder( Box::Flat, QskRgb::SaddleBrown ); - rectangle->setBackground( type, QGradient::SunnyMorning ); + rectangle->setWebGradient( type, QGradient::SunnyMorning ); } } @@ -113,19 +112,19 @@ static void addRectangles3( QskLinearBox* parent ) box = new MyRectangle( parent ); box->setBorder( Box::Sunken1, borderTheme ); - box->setGradient( QskGradient::Diagonal, Grey400, Grey500 ); + box->setGradient( Box::Diagonal, Grey400, Grey500 ); box = new MyRectangle( parent ); box->setBorder( Box::Raised2, borderTheme ); - box->setGradient( QskGradient::Vertical, Grey400, Grey500 ); + box->setGradient( Box::Vertical, Grey400, Grey500 ); box = new MyRectangle( parent ); box->setBorder( Box::Raised2, borderTheme ); - box->setBackground( Box::Vertical, QGradient::RiverCity, true ); + box->setWebGradient( Box::Vertical, QGradient::RiverCity, true ); box = new MyRectangle( parent ); box->setBorder( Box::Sunken2, borderTheme ); - box->setBackground( Box::Vertical, QGradient::RiverCity, false ); + box->setWebGradient( Box::Vertical, QGradient::RiverCity, false ); } static void addRectangles4( QskLinearBox* parent ) @@ -134,7 +133,7 @@ static void addRectangles4( QskLinearBox* parent ) Box::Horizontal, Box::Vertical, Box::Diagonal } ) { auto* box = new MyRoundedRectangle( parent ); - box->setBackground( type, QskRgb::OrangeRed ); + box->setTonalGradient( type, QskRgb::OrangeRed ); } } @@ -145,7 +144,7 @@ static void addRectangles5( QskLinearBox* parent ) { auto* box = new MyRoundedRectangle( parent ); box->setBorder( Box::Flat, QskRgb::RoyalBlue ); - box->setBackground( type, QskRgb::DeepPink ); + box->setTonalGradient( type, QskRgb::DeepPink ); } } @@ -163,19 +162,19 @@ static void addRectangles6( QskLinearBox* parent ) box = new MyRoundedRectangle( parent ); box->setBorder( Box::Sunken1, borderTheme ); - box->setGradient( QskGradient::Diagonal, Grey400, Grey500 ); + box->setGradient( Box::Diagonal, Grey400, Grey500 ); box = new MyRoundedRectangle( parent ); box->setBorder( Box::Raised2, borderTheme ); - box->setGradient( QskGradient::Vertical, Grey400, Grey500 ); + box->setGradient( Box::Vertical, Grey400, Grey500 ); box = new MyRoundedRectangle( parent ); box->setBorder( Box::Raised2, borderTheme ); - box->setGradient( QskGradient::Vertical, Lime300, Lime600 ); + box->setGradient( Box::Vertical, Lime300, Lime600 ); box = new MyRoundedRectangle( parent ); box->setBorder( Box::Sunken2, borderTheme ); - box->setGradient( QskGradient::Vertical, Lime600, Lime300 ); + box->setGradient( Box::Vertical, Lime600, Lime300 ); } static void addRectangles7( QskLinearBox* parent ) @@ -184,7 +183,7 @@ static void addRectangles7( QskLinearBox* parent ) Box::Horizontal, Box::Vertical, Box::Diagonal } ) { auto* box = new MyEllipse( parent ); - box->setBackground( type, QskRgb::SlateGrey ); + box->setTonalGradient( type, QskRgb::SlateGrey ); } } @@ -195,7 +194,7 @@ static void addRectangles8( QskLinearBox* parent ) { auto* box = new MyEllipse( parent ); box->setBorder( Box::Flat, QskRgb::RoyalBlue ); - box->setBackground( type, QskRgb::FireBrick ); + box->setTonalGradient( type, QskRgb::FireBrick ); } } @@ -213,53 +212,60 @@ static void addRectangles9( QskLinearBox* parent ) box = new MyEllipse( parent ); box->setBorder( Box::Sunken1, borderTheme ); - box->setGradient( QskGradient::Diagonal, Grey400, Grey500 ); + box->setGradient( Box::Diagonal, Grey400, Grey500 ); box = new MyEllipse( parent ); box->setBorder( Box::Raised2, borderTheme ); - box->setGradient( QskGradient::Vertical, Grey400, Grey500 ); + box->setGradient( Box::Vertical, Grey400, Grey500 ); box = new MyEllipse( parent ); box->setBorder( Box::Raised2, borderTheme ); - box->setGradient( QskGradient::Vertical, Lime200, Lime600 ); + box->setGradient( Box::Vertical, Lime200, Lime600 ); box = new MyEllipse( parent ); box->setBorder( Box::Sunken2, borderTheme ); - box->setGradient( QskGradient::Vertical, Lime600, Lime200 ); + box->setGradient( Box::Vertical, Lime600, Lime200 ); } static void addRectangles10( QskLinearBox* parent ) { - QColor borderTheme( "Indigo" ); + using namespace QskRgb; + + QColor borderTheme( Indigo ); // borderTheme.setAlpha( 100 ); + QskGradientStops stops; + stops += QskGradientStop( 0.0, DeepPink ); + stops += QskGradientStop( 0.5, DarkOrange ); + stops += QskGradientStop( 1.0, HotPink ); + Box* box; box = new Box( parent ); - box->setGradient( QskGradient::Horizontal, "DeepPink", "DarkOrange", "HotPink" ); + box->setGradient( Box::Horizontal, stops ); box = new Box( parent ); box->setBorderWidth( 10 ); box->setBorderGradient( borderTheme ); - box->setGradient( QskGradient::Diagonal, "DeepPink", "DarkOrange", "HotPink" ); + box->setGradient( Box::Diagonal, stops ); box = new Box( parent ); box->setShape( 100, Qt::RelativeSize ); box->setBorderWidth( 5 ); box->setBorderGradient( borderTheme ); - box->setGradient( QskGradient::Vertical, "DeepPink", "DarkOrange", "HotPink" ); + box->setGradient( Box::Vertical, stops ); box = new Box( parent ); box->setShape( 100, Qt::RelativeSize ); box->setBorderWidth( 5 ); box->setBorderGradient( borderTheme ); - box->setGradient( QskGradient::Diagonal, "DeepPink", "DarkOrange", "HotPink" ); + box->setGradient( Box::Diagonal, stops ); box = new Box( parent ); box->setShape( 100, Qt::RelativeSize ); box->setBorderWidth( 5, 20, 30, 5 ); box->setBorderGradient( borderTheme ); - box->setGradient( QskGradient::Vertical, "DeepPink", "DarkOrange", "HotPink" ); + box->setGradient( Box::Vertical, stops ); } static void addRectangles11( QskLinearBox* parent ) @@ -279,111 +285,109 @@ static void addRectangles11( QskLinearBox* parent ) bw[ i - 1 ] = 0; box->setBorderWidth( bw[ 0 ], bw[ 1 ], bw[ 2 ], bw[ 3 ] ); - box->setBackground( fillType[ i ], QskRgb::Sienna, i >= 3 ); + box->setTonalGradient( fillType[ i ], QskRgb::Sienna, i >= 3 ); } } static void addRectangles12( QskLinearBox* parent ) { - for ( auto orientation : { QskGradient::Vertical, - QskGradient::Horizontal, QskGradient::Diagonal } ) + for ( auto fillType : { Box::Vertical, Box::Horizontal, Box::Diagonal } ) { auto* box = new Box( parent ); box->setBorderWidth( 0 ); - box->setGradient( orientation, QskRgb::LightSlateGray ); + box->setTonalPalette( fillType, QskRgb::LightSlateGray ); } - for ( auto orientation : { QskGradient::Vertical, QskGradient::Diagonal } ) + for ( auto fillType : { Box::Vertical, Box::Diagonal } ) { auto* box = new Box( parent ); box->setBorder( Box::Flat, QskRgb::OrangeRed ); - box->setGradient( orientation, QskRgb::DodgerBlue ); + box->setTonalPalette( fillType, QskRgb::DodgerBlue ); } - for ( auto orientation : { QskGradient::Vertical, - QskGradient::Horizontal, QskGradient::Diagonal } ) + for ( auto fillType : { Box::Vertical, Box::Horizontal, Box::Diagonal } ) { auto* box = new Box( parent ); box->setBorderWidth( 0 ); box->setShape( 30, 40, Qt::RelativeSize ); - box->setGradient( orientation, QskRgb::LightSlateGray ); + box->setTonalPalette( fillType, QskRgb::LightSlateGray ); } - for ( auto orientation : { QskGradient::Vertical, QskGradient::Diagonal } ) + for ( auto fillType : { Box::Vertical, Box::Diagonal } ) { auto* box = new Box( parent ); box->setBorder( Box::Flat, QskRgb::OrangeRed ); box->setShape( 30, 40, Qt::RelativeSize ); - box->setGradient( orientation, QskRgb::DodgerBlue ); + box->setTonalPalette( fillType, QskRgb::DodgerBlue ); } - for ( auto orientation : { QskGradient::Vertical, - QskGradient::Horizontal, QskGradient::Diagonal } ) + for ( auto fillType : { Box::Vertical, Box::Horizontal, Box::Diagonal } ) { auto* box = new Box( parent ); box->setBorderWidth( 0 ); box->setShape( 100, 100, Qt::RelativeSize ); - box->setGradient( orientation, QskRgb::LightSlateGray ); + box->setTonalPalette( fillType, QskRgb::LightSlateGray ); } - for ( auto orientation : { QskGradient::Vertical, QskGradient::Diagonal } ) + for ( auto fillType : { Box::Vertical, Box::Diagonal } ) { auto* box = new Box( parent ); box->setBorder( Box::Flat, QskRgb::OrangeRed ); box->setShape( 100, 100, Qt::RelativeSize ); - box->setGradient( orientation, QskRgb::DodgerBlue ); + box->setTonalPalette( fillType, QskRgb::DodgerBlue ); } } static void addRectanglesRest( QskLinearBox* parent ) { + using namespace QskRgb; + Box* box; box = new Box( parent ); box->setBorderWidth( 20, 0, 40, 0 ); - box->setBorderGradient( { "DarkSeaGreen" } ); + box->setBorderGradient( DarkSeaGreen ); box = new Box( parent ); box->setShape( 40, Qt::RelativeSize ); box->setBorderWidth( 20, 10, 30, 15 ); - box->setBorderGradient( { "DarkOrange" } ); - box->setGradient( QskGradient::Vertical, "LightSteelBlue", "SteelBlue" ); + box->setBorderGradient( DarkOrange ); + box->setGradient( Box::Vertical, LightSteelBlue, SteelBlue ); box = new Box( parent ); box->setBorderWidth( 20, 0, 10, 20 ); - box->setBorderGradient( { "MediumSeaGreen" } ); - box->setGradient( "DodgerBlue" ); + box->setBorderGradient( MediumSeaGreen ); + box->setGradient( DodgerBlue ); box = new Box( parent ); box->setShape( 20, Qt::AbsoluteSize ); box->setBorderWidth( 2, 10, 40, 2 ); - box->setBorderGradient( { "Crimson" } ); + box->setBorderGradient( Crimson ); box->setGradient( QskRgb::WhiteSmoke ); box = new Box( parent ); box->setShape( 100, Qt::RelativeSize ); box->setBorderWidth( 5, 20, 5, 0 ); - box->setBorderGradient( { "CadetBlue" } ); - box->setGradient( QskGradient::Vertical, "Gainsboro", "Seashell", "LightGray" ); + box->setBorderGradient( { CadetBlue } ); + box->setGradient( Box::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 ); + + QskGradientStops stops[4]; + + stops[0] = { { 0.0, Qt::blue }, { 0.9, Qt::yellow }, { 1.0, Qt::darkRed } }; + stops[1] = { { 0.0, Qt::black }, { 0.3, Qt::white }, { 0.7, Qt::white }, { 1.0, Qt::black } }; + stops[2] = { { 0.0, Qt::green }, { 1.0, Qt::green } }; + stops[3] = { { 0.0, Qt::magenta }, { 1.0, Qt::cyan } }; + + box->setBorderGradients( stops[0], stops[1], stops[2], stops[3] ); if( fillType != Box::Unfilled ) - box->setBackground( fillType, QskRgb::CornflowerBlue ); + box->setTonalGradient( fillType, QskRgb::CornflowerBlue ); if( rounded ) box->setShape( 30, Qt::AbsoluteSize ); @@ -396,7 +400,7 @@ static void addColoredBorderRectangles2( QskLinearBox* parent, bool rounded, Box box->setBorderGradients( Qt::red, Qt::green, Qt::blue, Qt::yellow ); if( fillType != Box::Unfilled ) - box->setBackground( fillType, QskRgb::CornflowerBlue ); + box->setTonalGradient( fillType, QskRgb::CornflowerBlue ); if( rounded ) box->setShape( 30, Qt::AbsoluteSize ); @@ -406,26 +410,25 @@ static void addColoredBorderRectangles3( QskLinearBox* parent, bool rounded, Box { 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 ); + + QskGradientStops stops[4]; + + stops[0] = { { 0.0, Qt::yellow }, { 0.2, Qt::gray }, + { 0.6, Qt::magenta }, { 1.0, Qt::green } }; + + stops[1] = { { 0.0, Qt::darkYellow }, { 0.2, Qt::cyan }, { 1.0, Qt::darkMagenta } }; + + stops[2] = { { 0.0, Qt::red }, { 0.25, Qt::green }, + { 0.5, Qt::blue }, { 0.75, Qt::magenta }, { 1.0, Qt::cyan } }; + + stops[3] = { { 0.0, Qt::red }, { 0.3, Qt::green }, + { 0.7, Qt::blue }, { 1.0, Qt::cyan } }; + + box->setBorderGradients( stops[0], stops[1], stops[2], stops[3] ); + //box->setBorderGradients( stops[2], stops[2], stops[2], stops[2] ); if( fillType != Box::Unfilled ) - box->setBackground( fillType, QskRgb::CornflowerBlue ); + box->setTonalGradient( fillType, QskRgb::CornflowerBlue ); if( rounded ) box->setShape( 30, Qt::AbsoluteSize ); @@ -435,11 +438,11 @@ static void addColoredBorderRectangles4( QskLinearBox* parent, bool rounded, Box { Box* box = new Box( parent ); box->setBorderWidth( 20 ); - QskGradient gradient( Qt::Vertical, Qt::magenta, Qt::cyan ); - box->setBorderGradients( gradient, gradient, gradient, gradient ); + + box->setBorderGradient( QskGradient( Qt::magenta, Qt::cyan ) ); if( fillType != Box::Unfilled ) - box->setBackground( fillType, QskRgb::CornflowerBlue ); + box->setTonalGradient( fillType, QskRgb::CornflowerBlue ); if( rounded ) box->setShape( 30, Qt::AbsoluteSize ); @@ -449,14 +452,14 @@ static void addColoredBorderRectangles5( QskLinearBox* parent, bool rounded, Box { 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 ); + + const QskGradientStops stops = { { 0.0, Qt::black }, { 0.3, Qt::white }, + { 0.7, Qt::white }, { 1.0, Qt::black } }; + + box->setBorderGradient( stops ); if( fillType != Box::Unfilled ) - box->setBackground( fillType, QskRgb::CornflowerBlue ); + box->setTonalGradient( fillType, QskRgb::CornflowerBlue ); if( rounded ) box->setShape( { 10, 20, 20, 40 } ); diff --git a/examples/desktop/main.cpp b/examples/desktop/main.cpp index bec6c8c6..a80e38cc 100644 --- a/examples/desktop/main.cpp +++ b/examples/desktop/main.cpp @@ -7,13 +7,14 @@ #include #include -#include +#include #include #include #include #include #include #include +#include #include #include @@ -59,7 +60,7 @@ int main( int argc, char* argv[] ) QskSubWindowArea* area = new QskSubWindowArea(); area->setGradientHint( QskSubWindowArea::Panel, - QskGradient( QskGradient::Diagonal, "DarkSlateGray", "LightSlateGray" ) ); + QskLinearGradient( 0.0, 0.0, 1.0, 1.0, QskRgb::DarkSlateGray, QskRgb::LightSlateGray ) ); QRectF windowRect( 0, 0, 250, 250 ); diff --git a/examples/gallery/progressbar/ProgressBarPage.cpp b/examples/gallery/progressbar/ProgressBarPage.cpp index 4a5b5ae9..31917d0f 100644 --- a/examples/gallery/progressbar/ProgressBarPage.cpp +++ b/examples/gallery/progressbar/ProgressBarPage.cpp @@ -35,8 +35,7 @@ namespace colors += hctColor.toned( 45 ).rgb(); colors += hctColor.toned( 30 ).rgb(); - setBarGradient( QskGradient( orientation(), - qskBuildGradientStops( colors, true ) ) ); + setBarGradient( qskBuildGradientStops( colors, true ) ); } }; } diff --git a/examples/iotdashboard/Skin.cpp b/examples/iotdashboard/Skin.cpp index 0cdc82eb..af57abb6 100644 --- a/examples/iotdashboard/Skin.cpp +++ b/examples/iotdashboard/Skin.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -111,11 +112,11 @@ void Skin::initHints( const Palette& palette ) ed.setColor( TopBarItem::Item3 | QskAspect::TextColor, 0xfff99055 ); ed.setColor( TopBarItem::Item4 | QskAspect::TextColor, 0xff6776ff ); - // conical gradients are counterclockwise, so specify the 2nd color first: - ed.setHGradient( TopBarItem::Item1, 0xffff3122, 0xffff5c00 ); - ed.setHGradient( TopBarItem::Item2, 0xff6100ff, 0xff6776ff ); - ed.setHGradient( TopBarItem::Item3, 0xffff3122, 0xffffce50 ); - ed.setHGradient( TopBarItem::Item4, 0xff6100ff, 0xff6776ff ); + // arcs are counterclockwise, so specify the 2nd color first: + ed.setGradient( TopBarItem::Item1, 0xffff3122, 0xffff5c00 ); + ed.setGradient( TopBarItem::Item2, 0xff6100ff, 0xff6776ff ); + ed.setGradient( TopBarItem::Item3, 0xffff3122, 0xffffce50 ); + ed.setGradient( TopBarItem::Item4, 0xff6100ff, 0xff6776ff ); // the bar gradient is defined through the top bar items above ed.setArcMetrics( CircularProgressBar::Groove, { 8.53, 90, -360 } ); @@ -141,8 +142,8 @@ void Skin::initHints( const Palette& palette ) { ed.setBoxShape( subControl, 6 ); - QskGradient normal( Qt::Vertical, 0xff6776ff, 0xff6100ff ); - QskGradient bright( Qt::Vertical, 0xffff7d34, 0xffff3122 ); + QskLinearGradient normal( Qt::Vertical, 0xff6776ff, 0xff6100ff ); + QskLinearGradient bright( Qt::Vertical, 0xffff7d34, 0xffff3122 ); if ( subControl == RoundedIcon::PalePanel ) { @@ -197,9 +198,9 @@ void Skin::initHints( const Palette& palette ) ed.setBoxShape( LightDisplay::Panel, 100, Qt::RelativeSize ); ed.setArcMetrics( LightDisplay::ColdAndWarmArc, 8.785, 0, 180 ); - QskGradient coldGradient( Qt::Horizontal, - { { 0.0, 0xffff3122 }, { 0.2, 0xfffeeeb7 }, - { 0.3, 0xffa7b0ff }, { 0.5, 0xff6776ff }, { 1.0, Qt::black } } ); + const QskGradient coldGradient( + { { 0.0, 0xffff3122 }, { 0.2, 0xfffeeeb7 }, { 0.3, 0xffa7b0ff }, + { 0.5, 0xff6776ff }, { 1.0, Qt::black } } ); ed.setGradient( LightDisplay::ColdAndWarmArc, coldGradient ); ed.setMetric( LightDisplay::Tickmarks, 1 ); @@ -250,7 +251,7 @@ Skin::Palette DaytimeSkin::palette() const 0xfff4f4f4, Qt::black, 0xffe5e5e5, - { Qt::Vertical, { { 0.0, 0xffc4c4c4 }, { 0.5, 0xfff8f8f8 }, { 1.0, 0xffc4c4c4 } } } + { { { 0.0, 0xffc4c4c4 }, { 0.5, 0xfff8f8f8 }, { 1.0, 0xffc4c4c4 } } } }; } @@ -264,6 +265,6 @@ Skin::Palette NighttimeSkin::palette() const 0xff0c0c0c, Qt::white, 0xff1a1a1a, - { Qt::Vertical, { { 0.0, 0xff666666 }, { 0.5, 0xff222222 }, { 1.0, 0xff333333 } } } + { { { 0.0, 0xff666666 }, { 0.5, 0xff222222 }, { 1.0, 0xff333333 } } } }; } diff --git a/examples/qvgviewer/MainWindow.cpp b/examples/qvgviewer/MainWindow.cpp index dea32139..da9dd75b 100644 --- a/examples/qvgviewer/MainWindow.cpp +++ b/examples/qvgviewer/MainWindow.cpp @@ -61,7 +61,7 @@ class GraphicLabel : public QskGraphicLabel const int duration = 500; - const QskGradient oldGradient = background(); + const auto oldGradient = background(); setGradientHint( Panel, gradient ); // finally setup a smooth transition manually diff --git a/playground/dials/SkinFactory.cpp b/playground/dials/SkinFactory.cpp index 22a3e8d8..be82c98c 100644 --- a/playground/dials/SkinFactory.cpp +++ b/playground/dials/SkinFactory.cpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace { @@ -57,7 +58,7 @@ namespace ed.setStrutSize( Q::Knob, 30, 30 ); ed.setBoxShape( Q::Knob, 100, Qt::RelativeSize ); ed.setGradient( Q::Knob, - QskGradient( QskGradient::Diagonal, rgb2, rgb1 ) ); + QskLinearGradient( 0.0, 0.0, 1.0, 1.0, rgb2, rgb1 ) ); ed.setMetric( Q::Needle | QskAspect::Size, 2 ); ed.setMetric( Q::Needle | QskAspect::Margin, 10 ); diff --git a/playground/shapes/ShapeItem.cpp b/playground/shapes/ShapeItem.cpp index 1d3d6209..821f6bc0 100644 --- a/playground/shapes/ShapeItem.cpp +++ b/playground/shapes/ShapeItem.cpp @@ -42,73 +42,6 @@ static inline qreal effectivePenWidth( return width; } -namespace -{ - class ShapeNode : public QskShapeNode - { - public: - void updateShape( const QPainterPath& path, - const QTransform& transform, const QRectF& rect, const Gradient& gradient ) - { - if ( gradient.isMonochrome() ) - { - updateNode( path, transform, gradient.stops().first().color() ); - return; - } - - /* - Stupid code to map Gradient -> QGradient - Can be removed once Gradient has been merged into QskGradient. - */ - - switch( static_cast( gradient.type() ) ) - { - case QGradient::LinearGradient: - { - const auto& g = gradient.asLinearGradient(); - - QLinearGradient qgradient( g.start(), g.stop() ); - qgradient.setSpread( g.spread() ); - qgradient.setStops( g.qtStops() ); - - updateNode( path, transform, rect, &qgradient ); - - break; - } - case QGradient::RadialGradient: - { - const auto& g = gradient.asRadialGradient(); - - QRadialGradient qgradient( g.center(), g.radius() ); - qgradient.setSpread( g.spread() ); - qgradient.setStops( g.qtStops() ); - - updateNode( path, transform, rect, &qgradient ); - - break; - } - case QGradient::ConicalGradient: - { - const auto& g = gradient.asConicGradient(); - - QConicalGradient qgradient( g.center(), g.startAngle() ); - qgradient.setSpread( g.spread() ); - qgradient.setStops( g.qtStops() ); - - /* - Once ConicGradient has become QskConicGradient we do not - need QConicalGradient anymore and passing the spanAngle - as extra parameter can go away. - */ - updateNode( path, transform, rect, &qgradient, g.spanAngle() ); - - break; - } - } - } - }; -} - ShapeItem::ShapeItem( QQuickItem* parent ) : QskControl( parent ) { @@ -134,7 +67,7 @@ QPen ShapeItem::pen() const return m_pen; } -void ShapeItem::setGradient( const Gradient& gradient ) +void ShapeItem::setGradient( const QskGradient& gradient ) { if ( gradient != m_gradient ) { @@ -143,7 +76,7 @@ void ShapeItem::setGradient( const Gradient& gradient ) } } -const Gradient& ShapeItem::gradient() const +const QskGradient& ShapeItem::gradient() const { return m_gradient; } @@ -173,7 +106,7 @@ void ShapeItem::updateNode( QSGNode* parentNode ) const auto rect = contentsRect(); const auto pathRect = m_path.controlPointRect(); - auto fillNode = static_cast< ShapeNode* >( + auto fillNode = static_cast< QskShapeNode* >( QskSGNode::findChildNode( parentNode, FillRole ) ); auto borderNode = static_cast< QskStrokeNode* >( @@ -191,7 +124,7 @@ void ShapeItem::updateNode( QSGNode* parentNode ) { if ( fillNode == nullptr ) { - fillNode = new ShapeNode; + fillNode = new QskShapeNode; QskSGNode::setNodeRole( fillNode, FillRole ); parentNode->prependChildNode( fillNode ); @@ -205,7 +138,7 @@ void ShapeItem::updateNode( QSGNode* parentNode ) } const auto transform = ::transformForRects( pathRect, fillRect ); - fillNode->updateShape( m_path, transform, fillRect, m_gradient ); + fillNode->updateNode( m_path, transform, fillRect, m_gradient ); } else { diff --git a/playground/shapes/ShapeItem.h b/playground/shapes/ShapeItem.h index 16e05a25..70841e17 100644 --- a/playground/shapes/ShapeItem.h +++ b/playground/shapes/ShapeItem.h @@ -5,13 +5,11 @@ #pragma once -#include "Gradient.h" +#include #include #include #include -class Gradient; - class ShapeItem : public QskControl { Q_OBJECT @@ -23,8 +21,8 @@ class ShapeItem : public QskControl void setPen( const QPen& ); QPen pen() const; - void setGradient( const Gradient& ); - const Gradient& gradient() const; + void setGradient( const QskGradient& ); + const QskGradient& gradient() const; void setPath( const QPainterPath& ); QPainterPath path() const; @@ -36,6 +34,6 @@ class ShapeItem : public QskControl QPainterPath scaledPath( const QRectF& ) const; QPen m_pen; - Gradient m_gradient; + QskGradient m_gradient; QPainterPath m_path; }; diff --git a/playground/shapes/main.cpp b/playground/shapes/main.cpp index 302a2074..1451c79e 100644 --- a/playground/shapes/main.cpp +++ b/playground/shapes/main.cpp @@ -4,13 +4,15 @@ *****************************************************************************/ #include "ShapeItem.h" -#include "Gradient.h" #include #include #include #include #include +#include +#include +#include #include #include @@ -63,9 +65,32 @@ namespace shapeItem->setPath( path( SkinnyShapeFactory::Hexagon ) ); shapeItem->setPen( pen( QColorConstants::Svg::indigo ) ); - LinearGradient gradient( 0.0, 0.0, 0.2, 0.5 ); + QskLinearGradient gradient( 0.0, 0.0, 0.2, 0.5, QGradient::PhoenixStart ); gradient.setSpread( QGradient::ReflectSpread ); - gradient.setStops( QGradient::PhoenixStart ); + + shapeItem->setGradient( gradient ); + } + + { + auto shapeItem = new ShapeItem( this ); + shapeItem->setPath( path( SkinnyShapeFactory::Star ) ); + + const QVector< QskGradientStop > stops = + { { 0.5, QskRgb::RoyalBlue }, { 0.5, QskRgb::LemonChiffon } }; + + QskLinearGradient gradient( 0.0, 0.0, 0.05, 0.1, stops ); + gradient.setSpread( QGradient::RepeatSpread ); + + shapeItem->setGradient( gradient ); + } + { + auto shapeItem = new ShapeItem( this ); + shapeItem->setPath( path( SkinnyShapeFactory::Rectangle ) ); + + const QVector< QskGradientStop > stops = + { { 0.5, QskRgb::MediumVioletRed }, { 0.5, QskRgb::Navy } }; + + QskLinearGradient gradient( 0.5, 0.0, 0.5, 0.5, stops ); shapeItem->setGradient( gradient ); } @@ -84,11 +109,9 @@ namespace shapeItem->setPath( path( SkinnyShapeFactory::Rectangle ) ); shapeItem->setPen( pen( QColorConstants::Svg::indigo ) ); - RadialGradient gradient( 0.5, 0.5, 0.5 ); - + QskRadialGradient gradient; + gradient.setStops( QskRgb::LightYellow, QskRgb::MidnightBlue ); gradient.setSpread( QGradient::PadSpread ); - gradient.setStops( QColorConstants::Svg::lightyellow, - QColorConstants::Svg::midnightblue ); shapeItem->setGradient( gradient ); } @@ -97,23 +120,22 @@ namespace shapeItem->setPath( path( SkinnyShapeFactory::Ellipse ) ); - RadialGradient gradient( 0.5, 0.5, 0.5 ); - gradient.setSpread( QGradient::PadSpread ); QVector< QskGradientStop > stops; stops += QskGradientStop( 0.0, Qt::green ); stops += QskGradientStop( 0.2, Qt::green ); - stops += QskGradientStop( 0.201, Qt::red ); + stops += QskGradientStop( 0.2, Qt::red ); stops += QskGradientStop( 0.4, Qt::red ); - stops += QskGradientStop( 0.401, Qt::yellow ); + stops += QskGradientStop( 0.4, Qt::yellow ); stops += QskGradientStop( 0.6, Qt::yellow ); - stops += QskGradientStop( 0.601, Qt::cyan ); + stops += QskGradientStop( 0.6, Qt::cyan ); stops += QskGradientStop( 0.8, Qt::cyan ); - stops += QskGradientStop( 0.801, Qt::darkCyan ); + stops += QskGradientStop( 0.8, Qt::darkCyan ); stops += QskGradientStop( 1.0, Qt::darkCyan ); - gradient.setStops( stops ); + QskRadialGradient gradient( stops ); + gradient.setSpread( QGradient::PadSpread ); shapeItem->setGradient( gradient ); } @@ -121,13 +143,10 @@ namespace auto shapeItem = new ShapeItem( this ); shapeItem->setPath( path( SkinnyShapeFactory::Rectangle ) ); - shapeItem->setPen( pen( QColorConstants::Svg::indigo ) ); - - RadialGradient gradient( 0.5, 0.5, 0.25 ); - gradient.setCenter( 0.5, 0.7 ); + shapeItem->setPen( pen( QskRgb::Indigo ) ); + QskRadialGradient gradient( 0.5, 0.7, 0.25, QGradient::LilyMeadow ); gradient.setSpread( QGradient::RepeatSpread ); - gradient.setStops( QGradient::LilyMeadow ); shapeItem->setGradient( gradient ); } @@ -135,12 +154,10 @@ namespace auto shapeItem = new ShapeItem( this ); shapeItem->setPath( path( SkinnyShapeFactory::Rectangle ) ); - shapeItem->setPen( pen( QColorConstants::Svg::indigo ) ); - - RadialGradient gradient( 0.6, 0.4, 0.1 ); + shapeItem->setPen( pen( QskRgb::Indigo ) ); + QskRadialGradient gradient( 0.6, 0.4, 0.1, Qt::red, Qt::blue ); gradient.setSpread( QGradient::ReflectSpread ); - gradient.setStops( Qt::red, Qt::blue ); shapeItem->setGradient( gradient ); } @@ -158,7 +175,7 @@ namespace shapeItem->setPath( path( SkinnyShapeFactory::Ellipse ) ); - ConicGradient gradient( 0.5, 0.5, 30.0, 60.0 ); + QskConicGradient gradient( 0.5, 0.5, 30.0, 60.0 ); gradient.setSpread( QGradient::ReflectSpread ); gradient.setStops( QGradient::JuicyPeach ); @@ -169,7 +186,7 @@ namespace shapeItem->setPath( path( SkinnyShapeFactory::TriangleUp ) ); - ConicGradient gradient( 0.5, 0.5, 30.0, 60.0 ); + QskConicGradient gradient( 0.5, 0.5, 30.0, 60.0 ); gradient.setSpread( QGradient::RepeatSpread ); gradient.setStops( QGradient::WinterNeva ); @@ -180,7 +197,7 @@ namespace shapeItem->setPath( path( SkinnyShapeFactory::Arc ) ); - ConicGradient gradient( 0.5, 0.5, 300.0, -240.0 ); + QskConicGradient gradient( 0.5, 0.5, 300.0, -240.0 ); gradient.setStops( QGradient::SpikyNaga ); shapeItem->setGradient( gradient ); @@ -190,7 +207,7 @@ namespace shapeItem->setPath( path( SkinnyShapeFactory::Diamond ) ); - ConicGradient gradient( 0.5, 0.5, 45.0, 180.0 ); + QskConicGradient gradient( 0.5, 0.5, 45.0, 180.0 ); gradient.setStops( QGradient::FabledSunset ); gradient.setSpread( QGradient::ReflectSpread ); diff --git a/playground/shapes/shapes.pro b/playground/shapes/shapes.pro index fb2d05f5..bbf1741a 100644 --- a/playground/shapes/shapes.pro +++ b/playground/shapes/shapes.pro @@ -1,10 +1,8 @@ CONFIG += qskexample HEADERS += \ - Gradient.h \ ShapeItem.h \ SOURCES += \ - Gradient.cpp \ ShapeItem.cpp \ main.cpp diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 22cac9c0..8e3a8477 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include @@ -176,10 +176,10 @@ namespace void Editor::setSeparator( QskAspect aspect ) { - QskGradient gradient( QskGradient::Vertical, m_pal.lighter110, m_pal.darker125 ); + QskLinearGradient gradient( Qt::Vertical, m_pal.lighter110, m_pal.darker125 ); if ( aspect.placement() == QskAspect::Vertical ) - gradient.setOrientation( QskGradient::Horizontal ); + gradient.setOrientation( Qt::Horizontal ); setGradient( aspect, gradient ); setBoxShape( aspect, 0 ); @@ -193,7 +193,7 @@ void Editor::setButton( QskAspect aspect, PanelStyle style, qreal border ) #endif QskBoxBorderColors borderColors; - QskGradient gradient( QskGradient::Vertical ); + QskLinearGradient gradient( Qt::Vertical ); switch ( style ) { @@ -637,8 +637,7 @@ void Editor::setupTabButton() for ( auto placement : { A::Top, A::Bottom } ) { - setGradient( Q::Panel | placement, - QskGradient( Qt::Vertical, m_pal.lighter125, m_pal.lighter110 ) ); + setVGradient( Q::Panel | placement, m_pal.lighter125, m_pal.lighter110 ); for ( const auto state : { Q::Checked | A::NoState, Q::Checked | Q::Pressed } ) { diff --git a/src/common/QskGradient.cpp b/src/common/QskGradient.cpp index 496d22d4..4a471fca 100644 --- a/src/common/QskGradient.cpp +++ b/src/common/QskGradient.cpp @@ -6,7 +6,6 @@ #include "QskGradient.h" #include "QskRgbValue.h" -#include #include static void qskRegisterGradient() @@ -23,12 +22,6 @@ static void qskRegisterGradient() Q_CONSTRUCTOR_FUNCTION( qskRegisterGradient ) -static inline QskGradient::Orientation qskOrientation( Qt::Orientation o ) -{ - return ( o == Qt::Vertical ) - ? QskGradient::Vertical : QskGradient::Horizontal; -} - static inline bool qskIsGradientValid( const QskGradientStops& stops ) { if ( stops.isEmpty() ) @@ -57,66 +50,74 @@ static inline bool qskCanBeInterpolated( const QskGradient& from, const QskGradi if ( from.isMonochrome() || to.isMonochrome() ) return true; - return from.orientation() == to.orientation(); -} - -QskGradient::QskGradient( Orientation orientation ) noexcept - : m_orientation( orientation ) - , m_isDirty( false ) - , m_isValid( false ) - , m_isMonchrome( true ) - , m_isVisible( false ) -{ + return from.type() == to.type(); } QskGradient::QskGradient( const QColor& color ) - : QskGradient( Vertical ) { setStops( color ); } -QskGradient::QskGradient( Qt::Orientation orientation, - const QColor& startColor, const QColor& stopColor ) - : QskGradient( qskOrientation( orientation ), startColor, stopColor ) +QskGradient::QskGradient( const QColor& color1, const QColor& color2 ) { + setStops( color1, color2 ); } -QskGradient::QskGradient( Orientation orientation, - const QColor& startColor, const QColor& stopColor ) - : QskGradient( orientation ) +QskGradient::QskGradient( QGradient::Preset preset ) { - setStops( startColor, stopColor ); + setStops( qskBuildGradientStops( QGradient( preset ).stops() ) ); } -QskGradient::QskGradient( Qt::Orientation orientation, const QskGradientStops& stops ) - : QskGradient( qskOrientation( orientation ), stops ) -{ -} - -QskGradient::QskGradient( Orientation orientation, const QskGradientStops& stops ) - : QskGradient( orientation ) +QskGradient::QskGradient( const QVector< QskGradientStop >& stops ) { setStops( stops ); } -QskGradient::QskGradient( Qt::Orientation orientation, QGradient::Preset preset ) - : QskGradient( qskOrientation( orientation ), preset ) +QskGradient::QskGradient( const QskGradient& other ) noexcept + : m_stops( other.m_stops ) + , m_values{ other.m_values[0], other.m_values[1], + other.m_values[2], other.m_values[3], } + , m_type( other.m_type ) + , m_spread( other.m_spread ) + , m_isDirty( other.m_isDirty ) + , m_isValid( other.m_isValid ) + , m_isMonchrome( other.m_isMonchrome ) + , m_isVisible( other.m_isVisible ) { } -QskGradient::QskGradient( Orientation orientation, QGradient::Preset preset ) - : QskGradient( orientation ) -{ - setStops( qskBuildGradientStops( QGradient( preset ).stops() ) ); -} - QskGradient::~QskGradient() { } +QskGradient& QskGradient::operator=( const QskGradient& other ) noexcept +{ + m_type = other.m_type; + m_spread = other.m_spread; + m_stops = other.m_stops; + + m_values[0] = other.m_values[0]; + m_values[1] = other.m_values[1]; + m_values[2] = other.m_values[2]; + m_values[3] = other.m_values[3]; + + m_isDirty = other.m_isDirty; + m_isValid = other.m_isValid; + m_isMonchrome = other.m_isMonchrome; + m_isVisible = other.m_isVisible; + + return *this; +} + bool QskGradient::operator==( const QskGradient& other ) const noexcept { - return ( m_orientation == other.m_orientation ) && ( m_stops == other.m_stops ); + return ( m_type == other.m_type ) + && ( m_spread == other.m_spread ) + && ( m_values[0] == other.m_values[0] ) + && ( m_values[1] == other.m_values[1] ) + && ( m_values[2] == other.m_values[2] ) + && ( m_values[3] == other.m_values[3] ) + && ( m_stops == other.m_stops ); } void QskGradient::updateStatusBits() const @@ -162,17 +163,6 @@ bool QskGradient::isVisible() const noexcept return m_isVisible; } -void QskGradient::setOrientation( Qt::Orientation orientation ) noexcept -{ - setOrientation( qskOrientation( orientation ) ); -} - -void QskGradient::setOrientation( Orientation orientation ) noexcept -{ - // does not change m_isDirty - m_orientation = orientation; -} - void QskGradient::setStops( const QColor& color ) { m_stops = { { 0.0, color }, { 1.0, color } }; @@ -185,6 +175,12 @@ void QskGradient::setStops( const QColor& color1, const QColor& color2 ) m_isDirty = true; } +void QskGradient::setStops( QGradient::Preset preset ) +{ + const auto stops = qskBuildGradientStops( QGradient( preset ).stops() ); + setStops( stops ); +} + void QskGradient::setStops( const QskGradientStops& stops ) { if ( !stops.isEmpty() && !qskIsGradientValid( stops ) ) @@ -262,6 +258,11 @@ void QskGradient::setAlpha( int alpha ) m_isDirty = true; } +void QskGradient::setSpread( QGradient::Spread spread ) +{ + m_spread = spread; +} + void QskGradient::reverse() { if ( isMonochrome() ) @@ -314,13 +315,16 @@ QskGradient QskGradient::interpolated( const QskGradient& to, qreal ratio ) cons if ( qskCanBeInterpolated( *this, to ) ) { - // We simply interpolate stops + // We simply interpolate stops and values - gradient.setOrientation( to.orientation() ); + gradient = to; gradient.setStops( qskInterpolatedGradientStops( m_stops, isMonochrome(), to.m_stops, to.isMonochrome(), ratio ) ); + + for ( uint i = 0; i < sizeof( m_values ) / sizeof( m_values[0] ); i++ ) + gradient.m_values[i] = m_values[i] + ratio * ( to.m_values[i] - m_values[i] ); } else { @@ -338,14 +342,14 @@ QskGradient QskGradient::interpolated( const QskGradient& to, qreal ratio ) cons { const auto r = 2.0 * ratio; - gradient.setOrientation( orientation() ); + gradient = *this; gradient.setStops( qskInterpolatedGradientStops( m_stops, c, r ) ); } else { const auto r = 2.0 * ( ratio - 0.5 ); - gradient.setOrientation( to.orientation() ); + gradient = to; gradient.setStops( qskInterpolatedGradientStops( c, to.m_stops, r ) ); } } @@ -370,15 +374,57 @@ void QskGradient::clearStops() QskHashValue QskGradient::hash( QskHashValue seed ) const { - const auto o = orientation(); + auto hash = qHashBits( &m_type, sizeof( m_type ), seed ); + + if ( m_type != Stops ) + hash = qHashBits( m_values, sizeof( m_values ), seed ); - auto hash = qHashBits( &o, sizeof( o ), seed ); for ( const auto& stop : m_stops ) hash = stop.hash( hash ); return hash; } +#include "QskLinearGradient.h" +#include "QskRadialGradient.h" +#include "QskConicGradient.h" + +QskLinearGradient& QskGradient::asLinearGradient() +{ + assert( m_type == QskGradient::Linear ); + return *reinterpret_cast< QskLinearGradient* >( this ); +} + +const QskLinearGradient& QskGradient::asLinearGradient() const +{ + assert( m_type == QskGradient::Linear ); + return *reinterpret_cast< const QskLinearGradient* >( this ); +} + +QskRadialGradient& QskGradient::asRadialGradient() +{ + assert( m_type == QskGradient::Radial ); + return *reinterpret_cast< QskRadialGradient* >( this ); +} + +const QskRadialGradient& QskGradient::asRadialGradient() const +{ + assert( m_type == QskGradient::Radial ); + return *reinterpret_cast< const QskRadialGradient* >( this ); +} + +QskConicGradient& QskGradient::asConicGradient() +{ + assert( m_type == QskGradient::Conic ); + return *reinterpret_cast< QskConicGradient* >( this ); +} + +const QskConicGradient& QskGradient::asConicGradient() const +{ + assert( m_type == QskGradient::Conic ); + return *reinterpret_cast< const QskConicGradient* >( this ); +} + #ifndef QT_NO_DEBUG_STREAM #include @@ -388,46 +434,96 @@ QDebug operator<<( QDebug debug, const QskGradient& gradient ) QDebugStateSaver saver( debug ); debug.nospace(); - debug << "Gradient"; + debug << "QskGradient( "; - if ( !gradient.isValid() ) + switch ( gradient.type() ) { - debug << "()"; + case QskGradient::Linear: + { + debug << "L("; + + const auto& g = gradient.asLinearGradient(); + debug << g.start().x() << "," << g.start().y() + << "," << g.stop().x() << "," << g.stop().y() << ")"; + + break; + } + + case QskGradient::Radial: + { + debug << "R("; + + const auto& g = gradient.asRadialGradient(); + + debug << g.center().x() << "," << g.center().y() + << "," << g.radius() << ")"; + + break; + } + + case QskGradient::Conic: + { + debug << "C("; + + const auto& g = gradient.asConicGradient(); + + debug << g.center().x() << "," << g.center().y() + << ",[" << g.startAngle() << "," << g.spanAngle() << "])"; + break; + } + + case QskGradient::Stops: + { + debug << "S()"; + break; + } + } + + if ( gradient.stops().isEmpty() ) + { + debug << " ()"; } else { - debug << "( "; - if ( gradient.isMonochrome() ) { - QskRgb::debugColor( debug, gradient.startColor() ); + debug << ' '; + const auto color = gradient.stops().first().color(); + QskRgb::debugColor( debug, color ); } else { - const char o[] = { 'H', 'V', 'D' }; - debug << o[ gradient.orientation() ] << ", "; + debug << " ( "; - if ( gradient.stops().count() == 2 ) + const auto& stops = gradient.stops(); + for ( int i = 0; i < stops.count(); i++ ) { - QskRgb::debugColor( debug, gradient.startColor() ); - debug << ", "; - QskRgb::debugColor( debug, gradient.endColor() ); - } - else - { - const auto& stops = gradient.stops(); - for ( int i = 0; i < stops.count(); i++ ) - { - if ( i != 0 ) - debug << ", "; + if ( i != 0 ) + debug << ", "; - debug << stops[i]; - } + debug << stops[i]; } + + debug << " )"; } - debug << " )"; } + switch( gradient.spread() ) + { + case QGradient::RepeatSpread: + debug << " RP"; + break; + + case QGradient::ReflectSpread: + debug << " RF"; + break; + + case QGradient::PadSpread: + break; + } + + debug << " )"; + return debug; } diff --git a/src/common/QskGradient.h b/src/common/QskGradient.h index 83c3897b..ff81e3a9 100644 --- a/src/common/QskGradient.h +++ b/src/common/QskGradient.h @@ -11,6 +11,10 @@ #include #include +class QskLinearGradient; +class QskRadialGradient; +class QskConicGradient; + class QVariant; /* @@ -22,7 +26,6 @@ class QSK_EXPORT QskGradient { Q_GADGET - Q_PROPERTY( Orientation orientation READ orientation WRITE setOrientation ) Q_PROPERTY( QVector< QskGradientStop > stops READ stops WRITE setStops ) Q_PROPERTY( bool valid READ isValid ) @@ -30,43 +33,35 @@ class QSK_EXPORT QskGradient Q_PROPERTY( bool monochrome READ isMonochrome ) public: - // TODO: radial/canonical gradients + other diagonal linear gradients - enum Orientation + enum Type { - Horizontal, - Vertical, - Diagonal + Stops, + + Linear, + Radial, + Conic }; - Q_ENUM( Orientation ) + Q_ENUM( Type ) QskGradient() noexcept = default; - QskGradient( Orientation ) noexcept; QskGradient( Qt::GlobalColor ); QskGradient( QRgb ); QskGradient( const QColor& ); + QskGradient( const QColor&, const QColor& ); QskGradient( QGradient::Preset ); + QskGradient( const QVector< QskGradientStop >& ); - QskGradient( Qt::Orientation, const QVector< QskGradientStop >& ); - QskGradient( Qt::Orientation, const QColor&, const QColor& ); - QskGradient( Qt::Orientation, QGradient::Preset ); - - QskGradient( Orientation, const QVector< QskGradientStop >& ); - QskGradient( Orientation, const QColor&, const QColor& ); - QskGradient( Orientation, QGradient::Preset ); + QskGradient( const QskGradient& ) noexcept; ~QskGradient(); + QskGradient& operator=( const QskGradient& ) noexcept; + bool operator==( const QskGradient& ) const noexcept; bool operator!=( const QskGradient& ) const noexcept; - void setOrientation( Qt::Orientation ) noexcept; - void setOrientation( Orientation ) noexcept; - Orientation orientation() const noexcept; - - bool isHorizontal() const noexcept; - bool isVertical() const noexcept; - bool isTilted() const noexcept; + QskGradient::Type type() const noexcept; bool isValid() const noexcept; bool isMonochrome() const noexcept; @@ -88,6 +83,9 @@ class QSK_EXPORT QskGradient void setAlpha( int alpha ); + void setSpread( QGradient::Spread ); + QGradient::Spread spread() const noexcept; + void reverse(); QskGradient reversed() const; @@ -106,13 +104,37 @@ class QSK_EXPORT QskGradient int stepCount() const noexcept; + QskLinearGradient& asLinearGradient(); + const QskLinearGradient& asLinearGradient() const; + + QskRadialGradient& asRadialGradient(); + const QskRadialGradient& asRadialGradient() const; + + QskConicGradient& asConicGradient(); + const QskConicGradient& asConicGradient() const; + private: + friend class QskLinearGradient; + friend class QskRadialGradient; + friend class QskConicGradient; + + QskGradient( Type ) noexcept; + QskGradient( Type, qreal, qreal, qreal, qreal ) noexcept; + void updateStatusBits() const; private: QVector< QskGradientStop > m_stops; - Orientation m_orientation = Vertical; + /* + Linear: x1, y1, x2, y2 + Radial: centerX, centerY, radius, n/a + Conic: centerX, centerY, startAngle, spanAngle + */ + qreal m_values[4] = {}; + + Type m_type = Stops; + QGradient::Spread m_spread = QGradient::PadSpread; mutable bool m_isDirty = false; mutable bool m_isValid = false; @@ -122,6 +144,18 @@ class QSK_EXPORT QskGradient Q_DECLARE_METATYPE( QskGradient ) +inline QskGradient::QskGradient( QskGradient::Type type ) noexcept + : m_type( type ) +{ +} + +inline QskGradient::QskGradient( QskGradient::Type type, + qreal v1, qreal v2, qreal v3, qreal v4 ) noexcept + : m_values{ v1, v2, v3, v4 } + , m_type( type ) +{ +} + inline QskGradient::QskGradient( Qt::GlobalColor color ) : QskGradient( QColor( color ) ) { @@ -132,34 +166,14 @@ inline QskGradient::QskGradient( QRgb rgb ) { } -inline QskGradient::QskGradient( QGradient::Preset preset ) - : QskGradient( Vertical, preset ) -{ -} - inline bool QskGradient::operator!=( const QskGradient& other ) const noexcept { return !( *this == other ); } -inline QskGradient::Orientation QskGradient::orientation() const noexcept +inline QskGradient::Type QskGradient::type() const noexcept { - return m_orientation; -} - -inline bool QskGradient::isHorizontal() const noexcept -{ - return orientation() == Horizontal; -} - -inline bool QskGradient::isVertical() const noexcept -{ - return orientation() == Vertical; -} - -inline bool QskGradient::isTilted() const noexcept -{ - return orientation() == Diagonal; + return m_type; } inline const QskGradientStops& QskGradient::stops() const noexcept @@ -186,6 +200,11 @@ inline QColor QskGradient::endColor() const noexcept return m_stops.isEmpty() ? QColor() : m_stops.last().color(); } +inline QGradient::Spread QskGradient::spread() const noexcept +{ + return m_spread; +} + #ifndef QT_NO_DEBUG_STREAM class QDebug; diff --git a/src/controls/QskProgressBar.cpp b/src/controls/QskProgressBar.cpp index 11390281..3acc736c 100644 --- a/src/controls/QskProgressBar.cpp +++ b/src/controls/QskProgressBar.cpp @@ -6,7 +6,6 @@ #include "QskProgressBar.h" #include "QskIntervalF.h" -#include "QskGradient.h" #include "QskFunctions.h" #include "QskAnimator.h" #include "QskAspect.h" @@ -163,20 +162,12 @@ QskAspect::Placement QskProgressBar::effectivePlacement() const void QskProgressBar::setBarGradient( const QskGradient& gradient ) { - // An API where we set the stops only would be more accurate TODO ... - auto g = gradient; - - g.setOrientation( Qt::Horizontal ); - setGradientHint( Bar | QskAspect::Horizontal, g ); - - g.setOrientation( Qt::Vertical ); - setGradientHint( Bar | QskAspect::Vertical, g ); + setGradientHint( Bar, gradient ); } void QskProgressBar::resetBarGradient() { - resetColor( Bar | QskAspect::Vertical ); - resetColor( Bar | QskAspect::Horizontal ); + resetColor( Bar ); } QskGradient QskProgressBar::barGradient() const diff --git a/src/controls/QskProgressBarSkinlet.cpp b/src/controls/QskProgressBarSkinlet.cpp index 49f2ed46..ca84814f 100644 --- a/src/controls/QskProgressBarSkinlet.cpp +++ b/src/controls/QskProgressBarSkinlet.cpp @@ -7,6 +7,7 @@ #include "QskProgressBar.h" #include "QskIntervalF.h" #include "QskBoxBorderMetrics.h" +#include "QskLinearGradient.h" #include #include @@ -124,13 +125,26 @@ QSGNode* QskProgressBarSkinlet::updateBarNode( if ( !gradient.isVisible() ) return nullptr; - gradient.setOrientation( bar->orientation() ); - - if ( !gradient.isMonochrome() ) + if ( ( gradient.type() == QskGradient::Stops ) && !gradient.isMonochrome() ) { - const auto intv = qskBarInterval( bar ); - gradient = gradient.extracted( intv.lowerBound(), intv.upperBound() ); + /* + When having stops only we use a linear gradient, + where the colors are increasing in direction of the + progress value. We interprete the gradient as a + definition for the 100% situation and have to adjust + the stops for smaller bars. + For this situation it would be more convenient to + adjust the start/stop positions, but the box renderer is + not supporting this yet. TODO ... + */ + + const auto intv = qskBarInterval( bar ); + + auto stops = qskExtractedGradientStops( gradient.stops(), + intv.lowerBound(), intv.upperBound() ); + + gradient = QskLinearGradient( bar->orientation(), stops ); if ( bar->orientation() == Qt::Vertical || bar->layoutMirroring() ) gradient.reverse(); } diff --git a/src/controls/QskSkinHintTableEditor.cpp b/src/controls/QskSkinHintTableEditor.cpp index b238a0e0..bd4ea9a2 100644 --- a/src/controls/QskSkinHintTableEditor.cpp +++ b/src/controls/QskSkinHintTableEditor.cpp @@ -12,7 +12,7 @@ #include "QskBoxBorderMetrics.h" #include "QskBoxBorderColors.h" #include "QskShadowMetrics.h" -#include "QskGradient.h" +#include "QskLinearGradient.h" namespace { @@ -225,7 +225,7 @@ void QskSkinHintTableEditor::setHGradient( QskAspect aspect, const QColor& color1, const QColor& color2, QskStateCombination combination ) { - const QskGradient gradient( QskGradient::Horizontal, color1, color2 ); + const QskLinearGradient gradient( Qt::Horizontal, color1, color2 ); setGradient( aspect, gradient, combination ); } @@ -233,10 +233,18 @@ void QskSkinHintTableEditor::setVGradient( QskAspect aspect, const QColor& color1, const QColor& color2, QskStateCombination combination ) { - const QskGradient gradient( QskGradient::Vertical, color1, color2 ); + const QskLinearGradient gradient( Qt::Vertical, color1, color2 ); setGradient( aspect, gradient, combination ); } +void QskSkinHintTableEditor::setGradient( + QskAspect aspect, const QColor& color1, const QColor& color2, + QskStateCombination combination ) +{ + const QskGradient gradient( color1, color2 ); + setColorHint( aspect, gradient , combination ); +} + void QskSkinHintTableEditor::setGradient( QskAspect aspect, const QskGradient& gradient, QskStateCombination combination ) diff --git a/src/controls/QskSkinHintTableEditor.h b/src/controls/QskSkinHintTableEditor.h index 91dac5b4..380da2f7 100644 --- a/src/controls/QskSkinHintTableEditor.h +++ b/src/controls/QskSkinHintTableEditor.h @@ -118,6 +118,9 @@ class QSK_EXPORT QskSkinHintTableEditor void setVGradient( QskAspect, const QColor&, const QColor&, QskStateCombination = QskStateCombination() ); + void setGradient( QskAspect, const QColor&, const QColor&, + QskStateCombination = QskStateCombination() ); + void setGradient( QskAspect, const QskGradient&, QskStateCombination = QskStateCombination() ); diff --git a/src/nodes/QskArcRenderer.cpp b/src/nodes/QskArcRenderer.cpp index 0a9f0ad2..9c0c25c6 100644 --- a/src/nodes/QskArcRenderer.cpp +++ b/src/nodes/QskArcRenderer.cpp @@ -5,27 +5,30 @@ #include "QskArcRenderer.h" #include "QskArcMetrics.h" -#include "QskGradient.h" +#include "QskLinearGradient.h" #include #include void QskArcRenderer::renderArc(const QRectF& rect, - const QskArcMetrics& metrics, const QskGradient& gradient, - QPainter* painter ) + const QskArcMetrics& metrics, const QskGradient& gradient, QPainter* painter ) { - painter->setRenderHint( QPainter::Antialiasing, true ); + bool isRadial = false; - /* - horizontal is interpreted as in direction of the arc, - while vertical means from the inner to the outer border - */ + if ( gradient.type() == QskGradient::Linear ) + { + /* + Horizontal is interpreted as conic ( in direction of the arc ), + while Vertical means radial ( inner to outer border ) + */ + isRadial = gradient.asLinearGradient().isVertical(); + } QBrush brush; const auto qStops = qskToQGradientStops( gradient.stops() ); - if( gradient.orientation() == QskGradient::Vertical ) + if( isRadial ) { QRadialGradient radial( rect.center(), qMin( rect.width(), rect.height() ) ); radial.setStops( qStops ); @@ -40,6 +43,7 @@ void QskArcRenderer::renderArc(const QRectF& rect, brush = conical; } + painter->setRenderHint( QPainter::Antialiasing, true ); painter->setPen( QPen( brush, metrics.width(), Qt::SolidLine, Qt::FlatCap ) ); const int startAngle = qRound( metrics.startAngle() * 16 ); diff --git a/src/nodes/QskBoxNode.cpp b/src/nodes/QskBoxNode.cpp index 7fd09c30..f9b55540 100644 --- a/src/nodes/QskBoxNode.cpp +++ b/src/nodes/QskBoxNode.cpp @@ -37,6 +37,66 @@ static inline QskHashValue qskColorsHash( return fillGradient.hash( hash ); } +#if 1 + +#include "QskLinearGradient.h" + +static inline QskLinearGradient qskEffectiveGradient( const QskGradient& gradient ) +{ + QskLinearGradient g; + + if ( gradient.isVisible() ) + { + if ( gradient.isMonochrome() ) + { + g.setStops( gradient.startColor() ); + } + else + { + switch( gradient.type() ) + { + case QskGradient::Linear: + { + const auto& linearGradient = gradient.asLinearGradient(); + + if ( linearGradient.isVertical() ) + { + g.setOrientation( Qt::Vertical ); + } + else if ( linearGradient.isHorizontal() ) + { + g.setOrientation( Qt::Horizontal ); + } + else + { + g.setStart( 0.0, 0.0 ); + g.setStop( 1.0, 1.0 ); + } + + g.setStops( gradient.stops() ); + break; + } + case QskGradient::Radial: + case QskGradient::Conic: + { + qWarning() << "QskBoxNode does not support radial/conic gradients"; + g.setStops( Qt::black ); + break; + } + case QskGradient::Stops: + { + g.setStops( gradient.stops() ); + break; + } + } + } + } + + return g; +} + +#endif + class QskBoxNodePrivate final : public QSGGeometryNodePrivate { public: @@ -79,13 +139,16 @@ void QskBoxNode::setBoxData( const QRectF& rect, { Q_D( QskBoxNode ); - QskGradient fillGradient = gradient; + /* + QskBoxRenderer supports certain linear gradients only. + For everything else we would have to use a QskGradientMaterial instead. + + As a temporary solution we simply "convert" gradient into a + simple QskLinearGradient so that at least something is happening. + TODO ... + */ #if 1 - // Renderer is buggy for monochrome gradients with stops. TODO ... - if ( fillGradient.stops().count() > 2 && fillGradient.isMonochrome() ) - { - fillGradient.setStops( fillGradient.startColor() ); - } + const auto fillGradient = qskEffectiveGradient( gradient ); #endif const auto metricsHash = qskMetricsHash( shape, borderMetrics ); diff --git a/src/nodes/QskBoxRenderer.h b/src/nodes/QskBoxRenderer.h index 194f18a2..55a77e96 100644 --- a/src/nodes/QskBoxRenderer.h +++ b/src/nodes/QskBoxRenderer.h @@ -12,6 +12,7 @@ class QskBoxBorderMetrics; class QskBoxBorderColors; +class QskLinearGradient; class QskGradient; class QSGGeometry; @@ -32,7 +33,7 @@ class QSK_EXPORT QskBoxRenderer void renderBox( const QRectF&, const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, - const QskBoxBorderColors&, const QskGradient&, QSGGeometry& ); + const QskBoxBorderColors&, const QskLinearGradient&, QSGGeometry& ); class Quad { @@ -115,7 +116,7 @@ class QSK_EXPORT QskBoxRenderer void renderRect( const QRectF&, const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, - const QskBoxBorderColors&, const QskGradient&, QSGGeometry& ); + const QskBoxBorderColors&, const QskLinearGradient&, QSGGeometry& ); void renderRectellipseFill( const QRectF&, const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, QSGGeometry& ); @@ -125,12 +126,12 @@ class QSK_EXPORT QskBoxRenderer void renderRectellipse( const QRectF&, const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, - const QskBoxBorderColors&, const QskGradient&, QSGGeometry& ); + const QskBoxBorderColors&, const QskLinearGradient&, QSGGeometry& ); void renderDiagonalFill( const Metrics&, const QskGradient&, int lineCount, QskVertex::ColoredLine* ); - void renderRectFill( const Quad&, const QskGradient&, QskVertex::ColoredLine* ); + void renderRectFill( const Quad&, const QskLinearGradient&, QskVertex::ColoredLine* ); }; inline void QskBoxRenderer::renderBorder( @@ -155,7 +156,7 @@ inline void QskBoxRenderer::renderFill( inline void QskBoxRenderer::renderBox( const QRectF& rect, const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border, - const QskBoxBorderColors& borderColors, const QskGradient& gradient, + const QskBoxBorderColors& borderColors, const QskLinearGradient& gradient, QSGGeometry& geometry ) { if ( shape.isRectangle() ) diff --git a/src/nodes/QskBoxRendererEllipse.cpp b/src/nodes/QskBoxRendererEllipse.cpp index 111ad90a..ed1fc72e 100644 --- a/src/nodes/QskBoxRendererEllipse.cpp +++ b/src/nodes/QskBoxRendererEllipse.cpp @@ -4,7 +4,7 @@ *****************************************************************************/ #include "QskBoxRenderer.h" -#include "QskGradient.h" +#include "QskLinearGradient.h" #include "QskBoxBorderColors.h" #include "QskBoxBorderMetrics.h" @@ -868,13 +868,13 @@ namespace }; } -static inline Qt::Orientation qskQtOrientation( const QskGradient& gradient ) +static inline Qt::Orientation qskQtOrientation( const QskLinearGradient& gradient ) { return gradient.isVertical() ? Qt::Vertical : Qt::Horizontal; } static inline int qskFillLineCount( - const QskBoxRenderer::Metrics& metrics, const QskGradient& gradient ) + const QskBoxRenderer::Metrics& metrics, const QskLinearGradient& gradient ) { const int stepCount = metrics.corner[ 0 ].stepCount; @@ -1029,7 +1029,7 @@ static inline void qskRenderBorder( const QskBoxRenderer::Metrics& metrics, static inline void qskRenderFillRandom( const QskBoxRenderer::Metrics& metrics, - const QskGradient& gradient, ColoredLine* line ) + const QskLinearGradient& gradient, ColoredLine* line ) { const auto orientation = qskQtOrientation( gradient ); @@ -1047,7 +1047,7 @@ static inline void qskRenderFillRandom( static inline void qskRenderBoxRandom( const QskBoxRenderer::Metrics& metrics, const QskBoxBorderColors& borderColors, - const QskGradient& gradient, ColoredLine* fillLine, ColoredLine* borderLine ) + const QskLinearGradient& gradient, ColoredLine* fillLine, ColoredLine* borderLine ) { const auto& bc = borderColors; @@ -1099,7 +1099,7 @@ static inline void qskRenderBoxRandom( static inline void qskRenderFillOrdered( const QskBoxRenderer::Metrics& metrics, - const QskGradient& gradient, ColoredLine* lines ) + const QskLinearGradient& gradient, ColoredLine* lines ) { const auto& r = metrics.innerQuad; @@ -1333,7 +1333,7 @@ void QskBoxRenderer::renderRectellipseFill( void QskBoxRenderer::renderRectellipse( const QRectF& rect, const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border, - const QskBoxBorderColors& borderColors, const QskGradient& gradient, + const QskBoxBorderColors& borderColors, const QskLinearGradient& gradient, QSGGeometry& geometry ) { const Metrics metrics( rect, shape, border ); diff --git a/src/nodes/QskBoxRendererRect.cpp b/src/nodes/QskBoxRendererRect.cpp index 819e4c92..970ba876 100644 --- a/src/nodes/QskBoxRendererRect.cpp +++ b/src/nodes/QskBoxRendererRect.cpp @@ -8,7 +8,7 @@ #include "QskBoxRenderer.h" #include "QskBoxRendererColorMap.h" #include "QskFunctions.h" -#include "QskGradient.h" +#include "QskLinearGradient.h" #include "QskVertex.h" using namespace QskVertex; @@ -343,7 +343,7 @@ namespace } static inline void qskCreateFillOrdered( const QskBoxRenderer::Quad& rect, - const QskGradient& gradient, ColoredLine* line ) + const QskLinearGradient& gradient, ColoredLine* line ) { if ( gradient.isHorizontal() ) { @@ -371,11 +371,10 @@ static inline void qskCreateFillOrdered( const QskBoxRenderer::Quad& rect, } template< class ColorMap, class Line > -static inline void qskCreateFillRandom( - QskGradient::Orientation orientation, +static inline void qskCreateFillRandom( Qt::Orientation orientation, const QskBoxRenderer::Quad& r, const ColorMap& map, Line* line ) { - if ( orientation == QskGradient::Vertical ) + if ( orientation == Qt::Vertical ) { ( line++ )->setLine( r.left, r.top, r.right, r.top, map.colorAt( 0.0 ) ); ( line++ )->setLine( r.left, r.bottom, r.right, r.bottom, map.colorAt( 1.0 ) ); @@ -549,15 +548,13 @@ void QskBoxRenderer::renderRectFill( } const auto line = allocateLines< Line >( geometry, 2 ); - - qskCreateFillRandom( QskGradient::Vertical, - in, ColorMapSolid( Color() ), line ); + qskCreateFillRandom( Qt::Vertical, in, ColorMapSolid( Color() ), line ); } void QskBoxRenderer::renderRect( const QRectF& rect, const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border, const QskBoxBorderColors& borderColors, - const QskGradient& gradient, QSGGeometry& geometry ) + const QskLinearGradient& gradient, QSGGeometry& geometry ) { Q_UNUSED( shape ) @@ -624,7 +621,7 @@ void QskBoxRenderer::renderRect( if ( gd.isMonochrome() ) { const ColorMapSolid colorMap( gd.startColor() ); - qskCreateFillRandom( QskGradient::Vertical, in, colorMap, line ); + qskCreateFillRandom( Qt::Vertical, in, colorMap, line ); } else { @@ -641,8 +638,10 @@ void QskBoxRenderer::renderRect( if ( fillRandom ) { + const auto orientation = gd.isVertical() ? Qt::Vertical : Qt::Horizontal; + const ColorMapGradient colorMap( gd.startColor(), gd.endColor() ); - qskCreateFillRandom( gd.orientation(), in, colorMap, line ); + qskCreateFillRandom( orientation, in, colorMap, line ); } else { @@ -669,7 +668,7 @@ void QskBoxRenderer::renderRect( } void QskBoxRenderer::renderRectFill( const QskBoxRenderer::Quad& rect, - const QskGradient& gradient, QskVertex::ColoredLine* line ) + const QskLinearGradient& gradient, QskVertex::ColoredLine* line ) { qskCreateFillOrdered( rect, gradient, line ); } diff --git a/src/nodes/QskGradientMaterial.cpp b/src/nodes/QskGradientMaterial.cpp index cd32b23c..acfccaaf 100644 --- a/src/nodes/QskGradientMaterial.cpp +++ b/src/nodes/QskGradientMaterial.cpp @@ -7,7 +7,9 @@ #include "QskFunctions.h" #include "QskRgbValue.h" -#include +#include "QskLinearGradient.h" +#include "QskRadialGradient.h" +#include "QskConicGradient.h" QSK_QT_PRIVATE_BEGIN #include @@ -15,6 +17,7 @@ QSK_QT_PRIVATE_BEGIN #include QSK_QT_PRIVATE_END +#include #include // RHI shaders are supported by Qt 5.15 and Qt 6.x @@ -37,28 +40,15 @@ namespace class GradientTexture : public QSGPlainTexture { public: - GradientTexture( const QGradientStops& stops, QGradient::Spread spread ) + GradientTexture( const QskGradientStops& stops, QGradient::Spread spread ) { -#if 1 - /* - Once we got rid of QGradient we will have QskGradientStops - ( like in the gradients branch ). For the moment we have to copy - */ - - QskGradientStops qskStops; - qskStops.reserve( stops.size() ); - - for ( const auto& s : stops ) - qskStops += QskGradientStop( s.first, s.second ); -#endif /* Qt creates tables of 1024 colors, while Chrome, Firefox, and Android seem to use 256 colors only ( according to maybe outdated sources from the internet ), */ - - setImage( QskRgb::colorTable( 256, qskStops ) ); + setImage( QskRgb::colorTable( 256, stops ) ); const auto wrapMode = this->wrapMode( spread ); @@ -94,7 +84,7 @@ namespace } const void* rhi; - const QGradientStops stops; + const QskGradientStops stops; const QGradient::Spread spread; }; @@ -103,7 +93,7 @@ namespace size_t valus = seed + key.spread; for ( const auto& stop : key.stops ) - valus += stop.second.rgba(); + valus += stop.rgb(); return valus; } @@ -135,7 +125,7 @@ namespace } GradientTexture* texture( const void* rhi, - const QGradientStops& stops, QGradient::Spread spread ) + const QskGradientStops& stops, QGradient::Spread spread ) { const TextureHashKey key { rhi, stops, spread }; @@ -197,7 +187,7 @@ namespace class GradientMaterial : public QskGradientMaterial { public: - GradientMaterial( QGradient::Type type ) + GradientMaterial( QskGradient::Type type ) : QskGradientMaterial( type ) { setFlag( Blending | RequiresFullMatrix ); @@ -323,11 +313,11 @@ namespace { public: LinearMaterial() - : GradientMaterial( QGradient::LinearGradient ) + : GradientMaterial( QskGradient::Linear ) { } - bool setGradient( const QRectF& rect, const QLinearGradient& gradient ) + bool setGradient( const QRectF& rect, const QskLinearGradient& gradient ) { bool changed = false; @@ -350,8 +340,8 @@ namespace const QVector4D vector( rect.left() + gradient.start().x() * rect.width(), rect.top() + gradient.start().y() * rect.height(), - gradient.finalStop().x() * rect.width(), - gradient.finalStop().y() * rect.height() ); + gradient.stop().x() * rect.width(), + gradient.stop().y() * rect.height() ); if ( m_gradientVector != vector ) { @@ -476,7 +466,7 @@ namespace { public: RadialMaterial() - : GradientMaterial( QGradient::RadialGradient ) + : GradientMaterial( QskGradient::Radial ) { } @@ -486,7 +476,7 @@ namespace return &type; } - bool setGradient( const QRectF& rect, const QRadialGradient& gradient ) + bool setGradient( const QRectF& rect, const QskRadialGradient& gradient ) { bool changed = false; @@ -647,7 +637,7 @@ namespace { public: ConicMaterial() - : GradientMaterial( QGradient::ConicalGradient ) + : GradientMaterial( QskGradient::Conic ) { } @@ -657,7 +647,7 @@ namespace return &type; } - bool setGradient( const QRectF& rect, const QConicalGradient& gradient, qreal spanAngle ) + bool setGradient( const QRectF& rect, const QskConicGradient& gradient ) { bool changed = false; @@ -679,11 +669,11 @@ namespace // Angles as ratio of a rotation - float start = fmod( gradient.angle(), 360.0 ) / 360.0; + float start = fmod( gradient.startAngle(), 360.0 ) / 360.0; if ( start < 0.0) start += 1.0; - const float span = fmod( spanAngle, 360.0 ) / 360.0; + const float span = fmod( gradient.spanAngle(), 360.0 ) / 360.0; if ( center != m_center ) { @@ -826,7 +816,7 @@ namespace } } -QskGradientMaterial::QskGradientMaterial( QGradient::Type type ) +QskGradientMaterial::QskGradientMaterial( QskGradient::Type type ) : m_gradientType( type ) { } @@ -840,59 +830,54 @@ inline Material* qskEnsureMaterial( QskGradientMaterial* material ) return static_cast< Material* >( material ); } -bool QskGradientMaterial::updateGradient( - const QRectF& rect, const QGradient* g, qreal extraValue ) +bool QskGradientMaterial::updateGradient( const QRectF& rect, const QskGradient& gradient ) { - Q_ASSERT( g ); - - if ( g == nullptr ) - return false; - - auto& gradient = *g; - Q_ASSERT( gradient.type() == m_gradientType ); if ( gradient.type() != m_gradientType ) return false; - switch ( static_cast< int >( gradient.type() ) ) + switch ( gradient.type() ) { - case QGradient::LinearGradient: + case QskGradient::Linear: { auto material = static_cast< LinearMaterial* >( this ); - return material->setGradient( rect, - *reinterpret_cast< const QLinearGradient* >( g ) ); + return material->setGradient( rect, gradient.asLinearGradient() ); } - case QGradient::RadialGradient: + case QskGradient::Radial: { auto material = static_cast< RadialMaterial* >( this ); - return material->setGradient( rect, - *reinterpret_cast< const QRadialGradient* >( g ) ); + return material->setGradient( rect, gradient.asRadialGradient() ); } - case QGradient::ConicalGradient: + case QskGradient::Conic: { auto material = static_cast< ConicMaterial* >( this ); - return material->setGradient( rect, - *reinterpret_cast< const QConicalGradient* >( g ), extraValue ); + return material->setGradient( rect, gradient.asConicGradient() ); + } + + default: + { + qWarning( "Invalid gradient type" ); + break; } } return false; } -QskGradientMaterial* QskGradientMaterial::createMaterial( QGradient::Type gradientType ) +QskGradientMaterial* QskGradientMaterial::createMaterial( QskGradient::Type gradientType ) { switch ( gradientType ) { - case QGradient::LinearGradient: + case QskGradient::Linear: return new LinearMaterial(); - case QGradient::RadialGradient: + case QskGradient::Radial: return new RadialMaterial(); - case QGradient::ConicalGradient: + case QskGradient::Conic: return new ConicMaterial(); default: diff --git a/src/nodes/QskGradientMaterial.h b/src/nodes/QskGradientMaterial.h index 38ff3a53..7ba60ebd 100644 --- a/src/nodes/QskGradientMaterial.h +++ b/src/nodes/QskGradientMaterial.h @@ -7,39 +7,39 @@ #define QSK_GRADIENT_MATERIAL #include "QskGlobal.h" -#include +#include "QskGradient.h" #include class QSK_EXPORT QskGradientMaterial : public QSGMaterial { public: - static QskGradientMaterial* createMaterial( QGradient::Type ); + static QskGradientMaterial* createMaterial( QskGradient::Type ); - bool updateGradient( const QRectF&, const QGradient*, qreal ); - QGradient::Type gradientType() const; + bool updateGradient( const QRectF&, const QskGradient& ); + QskGradient::Type gradientType() const; - const QGradientStops& stops() const; + const QskGradientStops& stops() const; QGradient::Spread spread() const; protected: - QskGradientMaterial( QGradient::Type ); + QskGradientMaterial( QskGradient::Type ); - void setStops( const QGradientStops& ); + void setStops( const QskGradientStops& ); void setSpread( QGradient::Spread ); private: - const QGradient::Type m_gradientType; + const QskGradient::Type m_gradientType; - QGradientStops m_stops; + QskGradientStops m_stops; QGradient::Spread m_spread = QGradient::PadSpread; }; -inline QGradient::Type QskGradientMaterial::gradientType() const +inline QskGradient::Type QskGradientMaterial::gradientType() const { return m_gradientType; } -inline void QskGradientMaterial::setStops( const QGradientStops& stops ) +inline void QskGradientMaterial::setStops( const QskGradientStops& stops ) { m_stops = stops; } @@ -49,7 +49,7 @@ inline void QskGradientMaterial::setSpread( QGradient::Spread spread ) m_spread = spread; } -inline const QGradientStops& QskGradientMaterial::stops() const +inline const QskGradientStops& QskGradientMaterial::stops() const { return m_stops; } diff --git a/src/nodes/QskShapeNode.cpp b/src/nodes/QskShapeNode.cpp index d91ca665..c0b82110 100644 --- a/src/nodes/QskShapeNode.cpp +++ b/src/nodes/QskShapeNode.cpp @@ -5,8 +5,9 @@ #include "QskShapeNode.h" #include "QskGradientMaterial.h" +#include "QskGradient.h" +#include "QskLinearGradient.h" -#include #include QSK_QT_PRIVATE_BEGIN @@ -15,6 +16,14 @@ QSK_QT_PRIVATE_BEGIN #include QSK_QT_PRIVATE_END +static inline QskGradient qskEffectiveGradient( const QskGradient& gradient ) +{ + if ( gradient.type() == QskGradient::Stops ) + return QskLinearGradient( Qt::Vertical, gradient.stops() ); + + return gradient; +} + static void qskUpdateGeometry( const QPainterPath& path, const QTransform& transform, QSGGeometry& geometry ) { @@ -67,36 +76,6 @@ static inline void qskResetGeometry( QskShapeNode* node ) } } -static inline bool qskIsGradientVisible( const QGradient* gradient ) -{ - if ( gradient && gradient->type() != QGradient::NoGradient ) - { - for ( const auto& stop : gradient->stops() ) - { - if ( stop.second.alpha() > 0 ) - return true; - } - } - - return false; -} - -static inline bool qskIsGradientMonochrome( const QGradient* gradient ) -{ - if ( gradient && gradient->type() != QGradient::NoGradient ) - { - const auto stops = gradient->stops(); - - for ( int i = 1; i < stops.count(); i++ ) - { - if ( stops[i].second != stops[i - 1].second ) - return false; - } - } - - return true; -} - class QskShapeNodePrivate final : public QSGGeometryNodePrivate { public: @@ -107,7 +86,7 @@ class QskShapeNodePrivate final : public QSGGeometryNodePrivate } QSGGeometry geometry; - QGradient::Type gradientType = QGradient::NoGradient; + int gradientType = -1; /* Is there a better way to find out if the path has changed @@ -149,10 +128,10 @@ void QskShapeNode::updateNode( const QPainterPath& path, markDirty( QSGNode::DirtyGeometry ); } - if ( material() == nullptr || d->gradientType != QGradient::NoGradient ) + if ( material() == nullptr || d->gradientType >= 0 ) { setMaterial( new QSGFlatColorMaterial() ); - d->gradientType = QGradient::NoGradient; + d->gradientType = -1; } const auto c = color.toRgb(); @@ -166,12 +145,11 @@ void QskShapeNode::updateNode( const QPainterPath& path, } void QskShapeNode::updateNode( const QPainterPath& path, - const QTransform& transform, const QRectF& rect, - const QGradient* gradient, qreal extraValue ) + const QTransform& transform, const QRectF& rect, const QskGradient& gradient ) { Q_D( QskShapeNode ); - if ( path.isEmpty() || !qskIsGradientVisible( gradient ) ) + if ( path.isEmpty() || !gradient.isVisible() ) { d->path = QPainterPath(); qskResetGeometry( this ); @@ -179,9 +157,9 @@ void QskShapeNode::updateNode( const QPainterPath& path, return; } - if ( qskIsGradientMonochrome( gradient ) ) + if ( gradient.isMonochrome() ) { - updateNode( path, transform, gradient->stops().first().first ); + updateNode( path, transform, gradient.stops().first().color() ); return; } @@ -194,14 +172,18 @@ void QskShapeNode::updateNode( const QPainterPath& path, markDirty( QSGNode::DirtyGeometry ); } - if ( ( material() == nullptr ) || ( gradient->type() != d->gradientType ) ) + const auto effectiveGradient = qskEffectiveGradient( gradient ); + + const auto gradientType = effectiveGradient.type(); + + if ( ( material() == nullptr ) || ( gradientType != d->gradientType ) ) { - setMaterial( QskGradientMaterial::createMaterial( gradient->type() ) ); - d->gradientType = gradient->type(); + setMaterial( QskGradientMaterial::createMaterial( gradientType ) ); + d->gradientType = gradientType; } auto gradientMaterial = static_cast< QskGradientMaterial* >( material() ); - if ( gradientMaterial->updateGradient( rect, gradient, extraValue ) ) + if ( gradientMaterial->updateGradient( rect, effectiveGradient ) ) markDirty( QSGNode::DirtyMaterial ); } diff --git a/src/nodes/QskShapeNode.h b/src/nodes/QskShapeNode.h index 19a96977..3652b204 100644 --- a/src/nodes/QskShapeNode.h +++ b/src/nodes/QskShapeNode.h @@ -9,7 +9,7 @@ #include "QskGlobal.h" #include -class QGradient; +class QskGradient; class QColor; class QPainterPath; @@ -21,7 +21,7 @@ class QSK_EXPORT QskShapeNode : public QSGGeometryNode QskShapeNode(); void updateNode( const QPainterPath&, const QTransform&, - const QRectF&, const QGradient*, qreal = 0.0 ); + const QRectF&, const QskGradient& ); void updateNode( const QPainterPath&, const QTransform&, const QColor& ); diff --git a/src/nodes/shaders/boxshadow.frag.qsb b/src/nodes/shaders/boxshadow.frag.qsb index 11aefa91..e5d35e43 100644 Binary files a/src/nodes/shaders/boxshadow.frag.qsb and b/src/nodes/shaders/boxshadow.frag.qsb differ diff --git a/src/nodes/shaders/boxshadow.vert.qsb b/src/nodes/shaders/boxshadow.vert.qsb index df541f21..40cab02d 100644 Binary files a/src/nodes/shaders/boxshadow.vert.qsb and b/src/nodes/shaders/boxshadow.vert.qsb differ diff --git a/src/nodes/shaders/gradientconic.frag.qsb b/src/nodes/shaders/gradientconic.frag.qsb index 30441f42..e6d57a32 100644 Binary files a/src/nodes/shaders/gradientconic.frag.qsb and b/src/nodes/shaders/gradientconic.frag.qsb differ diff --git a/src/nodes/shaders/gradientconic.vert.qsb b/src/nodes/shaders/gradientconic.vert.qsb index 82ce7014..40e58729 100644 Binary files a/src/nodes/shaders/gradientconic.vert.qsb and b/src/nodes/shaders/gradientconic.vert.qsb differ diff --git a/src/nodes/shaders/gradientlinear.frag.qsb b/src/nodes/shaders/gradientlinear.frag.qsb index 3e333be4..94221b97 100644 Binary files a/src/nodes/shaders/gradientlinear.frag.qsb and b/src/nodes/shaders/gradientlinear.frag.qsb differ diff --git a/src/nodes/shaders/gradientlinear.vert.qsb b/src/nodes/shaders/gradientlinear.vert.qsb index 196eefc9..b374d361 100644 Binary files a/src/nodes/shaders/gradientlinear.vert.qsb and b/src/nodes/shaders/gradientlinear.vert.qsb differ diff --git a/src/nodes/shaders/gradientradial.frag.qsb b/src/nodes/shaders/gradientradial.frag.qsb index 14e004bd..69e6faaa 100644 Binary files a/src/nodes/shaders/gradientradial.frag.qsb and b/src/nodes/shaders/gradientradial.frag.qsb differ diff --git a/src/nodes/shaders/gradientradial.vert.qsb b/src/nodes/shaders/gradientradial.vert.qsb index 159077be..29129e61 100644 Binary files a/src/nodes/shaders/gradientradial.vert.qsb and b/src/nodes/shaders/gradientradial.vert.qsb differ diff --git a/src/src.pro b/src/src.pro index c5021646..74a476a0 100644 --- a/src/src.pro +++ b/src/src.pro @@ -27,6 +27,9 @@ HEADERS += \ common/QskGlobal.h \ common/QskGradient.h \ common/QskGradientStop.h \ + common/QskConicGradient.h \ + common/QskLinearGradient.h \ + common/QskRadialGradient.h \ common/QskHctColor.h \ common/QskIntervalF.h \ common/QskMargins.h \ @@ -55,6 +58,9 @@ SOURCES += \ common/QskBoxHints.cpp \ common/QskFunctions.cpp \ common/QskGradient.cpp \ + common/QskConicGradient.cpp \ + common/QskLinearGradient.cpp \ + common/QskRadialGradient.cpp \ common/QskGradientStop.cpp \ common/QskHctColor.cpp \ common/QskIntervalF.cpp \