playground for gradient fix testing
This commit is contained in:
parent
9f9fafe9ef
commit
d9be53e7a1
|
@ -2,6 +2,7 @@ add_subdirectory(anchors)
|
|||
add_subdirectory(dials)
|
||||
add_subdirectory(dialogbuttons)
|
||||
add_subdirectory(gradients)
|
||||
add_subdirectory(gradient_fix)
|
||||
add_subdirectory(invoker)
|
||||
add_subdirectory(shadows)
|
||||
add_subdirectory(shapes)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
############################################################################
|
||||
# QSkinny - Copyright (C) The authors
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
############################################################################
|
||||
|
||||
qsk_add_example(gradient_fix main.cpp)
|
|
@ -0,0 +1,285 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) The authors
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#include <QskObjectCounter.h>
|
||||
#include <QskTabBar.h>
|
||||
#include <QskTabView.h>
|
||||
#include <QskWindow.h>
|
||||
#include <QskSkinlet.h>
|
||||
#include <QskBoxNode.h>
|
||||
#include <QskTextNode.h>
|
||||
#include <QskSGNode.h>
|
||||
#include <QskBoxShadowNode.h>
|
||||
#include <QskBoxBorderColors.h>
|
||||
#include <QskBoxBorderMetrics.h>
|
||||
#include <QskGradientDirection.h>
|
||||
#include <QskBoxShapeMetrics.h>
|
||||
#include <QskLinearBox.h>
|
||||
#include <QskPushButton.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <SkinnyShortcut.h>
|
||||
|
||||
double qskMapValueRange( double value, double srcMin, double srcMax, double dstMin, double dstMax )
|
||||
{
|
||||
value = std::min( std::max( value, srcMin ), srcMax );
|
||||
double percentage = ( value - srcMin ) / ( srcMax - srcMin );
|
||||
double mappedValue = dstMin + percentage * ( dstMax - dstMin );
|
||||
return mappedValue;
|
||||
}
|
||||
|
||||
QColor extracted( const QskGradient& gradient, qreal ratio )
|
||||
{
|
||||
// Ensure the factor is within the [0, 1] range
|
||||
ratio = qBound< qreal >( 0.0, ratio, 1.0 );
|
||||
|
||||
// Extract RGB components of the start and end colors
|
||||
int startRed, startGreen, startBlue, startAlpha;
|
||||
gradient.startColor().getRgb( &startRed, &startGreen, &startBlue, &startAlpha );
|
||||
|
||||
int endRed, endGreen, endBlue, endAlpha;
|
||||
gradient.endColor().getRgb( &endRed, &endGreen, &endBlue, &endAlpha );
|
||||
|
||||
// Linearly interpolate each color component
|
||||
int interpolatedRed = static_cast< int >( startRed + ratio * ( endRed - startRed ) );
|
||||
int interpolatedGreen = static_cast< int >( startGreen + ratio * ( endGreen - startGreen ) );
|
||||
int interpolatedBlue = static_cast< int >( startBlue + ratio * ( endBlue - startBlue ) );
|
||||
int interpolatedAlpha = static_cast< int >( startAlpha + ratio * ( endAlpha - startAlpha ) );
|
||||
|
||||
// Create and return the interpolated color
|
||||
return QColor( interpolatedRed, interpolatedGreen, interpolatedBlue, interpolatedAlpha );
|
||||
}
|
||||
|
||||
QskGradient extracted( const QskGradient& gradient, qreal from, qreal to )
|
||||
{
|
||||
const auto stops = gradient.stops();
|
||||
|
||||
if ( stops.count() == 0 )
|
||||
return {};
|
||||
if ( stops.count() == 1 )
|
||||
return stops[ 0 ].color();
|
||||
|
||||
from = qBound( 0.0, from, 1.0 );
|
||||
to = qBound( 0.0, to, 1.0 );
|
||||
|
||||
// returns the stop indexes that contain 'from'
|
||||
const auto fromIndex = [ & ]() {
|
||||
for ( int i = 0; i < stops.count() - 1; ++i )
|
||||
{
|
||||
if ( stops[ i ].position() <= from && from <= stops[ i + 1 ].position() )
|
||||
{
|
||||
return std::make_pair( i, i + 1 );
|
||||
}
|
||||
}
|
||||
return std::pair< int, int >{ -1, -1 };
|
||||
}();
|
||||
|
||||
// returns the stop indexes that contain 'to'
|
||||
const auto toIndex = [ & ]() {
|
||||
for ( int i = stops.count() - 1; i > 0; --i )
|
||||
{
|
||||
if ( stops[ i - 1 ].position() <= to && to <= stops[ i ].position() )
|
||||
{
|
||||
return std::make_pair( i - 1, i );
|
||||
}
|
||||
}
|
||||
return std::pair< int, int >{ -1, -1 };
|
||||
}();
|
||||
|
||||
Q_ASSERT( fromIndex.first < toIndex.second );
|
||||
|
||||
const auto fromColor = [ & ]() {
|
||||
const auto p = qskMapValueRange( from, stops[ fromIndex.first ].position(),
|
||||
stops[ fromIndex.second ].position(), 0.0, 1.0 );
|
||||
return extracted(
|
||||
{ stops[ fromIndex.first ].color(), stops[ fromIndex.second ].color() }, p );
|
||||
}();
|
||||
|
||||
const auto toColor = [ & ]() {
|
||||
const auto p = qskMapValueRange(
|
||||
to, stops[ toIndex.first ].position(), stops[ toIndex.second ].position(), 0.0, 1.0 );
|
||||
return extracted( { stops[ toIndex.first ].color(), stops[ toIndex.second ].color() }, p );
|
||||
}();
|
||||
|
||||
QskGradient newGradient;
|
||||
newGradient.setLinearDirection( Qt::Horizontal );
|
||||
QskGradientStops newStops;
|
||||
newStops << QskGradientStop{ 0.0, fromColor };
|
||||
|
||||
for ( int i = fromIndex.second; i < toIndex.second; ++i )
|
||||
{
|
||||
const auto p = qskMapValueRange( stops[ i ].position(), from, to, 0.0, 1.0 );
|
||||
newStops << QskGradientStop{ p, stops[ i ].color() };
|
||||
}
|
||||
|
||||
newStops << QskGradientStop{ 1.0, toColor };
|
||||
newGradient.setStops( newStops );
|
||||
|
||||
Q_ASSERT( newGradient.stops().count() <= gradient.stops().count() );
|
||||
|
||||
return newGradient;
|
||||
}
|
||||
|
||||
class Control : public QskControl
|
||||
{
|
||||
public:
|
||||
QSK_SUBCONTROLS( Gradient, GradientStart, GradientStop )
|
||||
|
||||
Control( QQuickItem* parent = nullptr )
|
||||
: QskControl( parent )
|
||||
{
|
||||
setAcceptedMouseButtons( Qt::LeftButton | Qt::RightButton );
|
||||
setPositionHint( GradientStart, 0.0 );
|
||||
setPositionHint( GradientStop, 1.0 );
|
||||
}
|
||||
|
||||
void mouseMoveEvent( QMouseEvent* event ) override
|
||||
{
|
||||
if ( event->buttons() == Qt::LeftButton )
|
||||
setPositionHint( GradientStart, event->pos().x() / width() );
|
||||
if ( event->buttons() == Qt::RightButton )
|
||||
setPositionHint( GradientStop, event->pos().x() / width() );
|
||||
}
|
||||
|
||||
void mousePressEvent( QMouseEvent* event ) override
|
||||
{
|
||||
}
|
||||
|
||||
void mouseReleaseEvent( QMouseEvent* event ) override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
QSK_SUBCONTROL( Control, Gradient )
|
||||
QSK_SUBCONTROL( Control, GradientStart )
|
||||
QSK_SUBCONTROL( Control, GradientStop )
|
||||
|
||||
class Skinlet : public QskSkinlet
|
||||
{
|
||||
public:
|
||||
enum NodeRoles
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C
|
||||
};
|
||||
Skinlet( QskSkin* skin = nullptr )
|
||||
: QskSkinlet( skin )
|
||||
{
|
||||
setNodeRoles( { A, B, C } );
|
||||
}
|
||||
|
||||
QSGNode* updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const override
|
||||
{
|
||||
struct Node : QSGNode
|
||||
{
|
||||
Node()
|
||||
{
|
||||
appendChildNode( new QskBoxNode );
|
||||
appendChildNode( new QskTextNode );
|
||||
}
|
||||
};
|
||||
|
||||
const auto r = static_cast< const QskControl* >( skinnable )->contentsRect();
|
||||
auto g = skinnable->gradientHint( Control::Gradient );
|
||||
g.setLinearDirection( Qt::Horizontal );
|
||||
|
||||
const auto from = skinnable->positionHint( Control::GradientStart );
|
||||
const auto to = skinnable->positionHint( Control::GradientStop );
|
||||
|
||||
const auto x1 = qskMapValueRange( from, 0.0, 1.0, r.left(), r.right() );
|
||||
const auto x2 = qskMapValueRange( to, 0.0, 1.0, r.left(), r.right() );
|
||||
const auto y1 = 0.0;
|
||||
const auto y2 = r.height() / 3;
|
||||
const auto rect = QRectF{ QPointF{ x1, y1 }, QPointF{ x2, y2 } };
|
||||
const auto dy = r.height() / 3;
|
||||
|
||||
if ( nodeRole == A )
|
||||
{
|
||||
const auto rect = QRectF{ r.topLeft(), QSizeF{ r.width(), r.height() / 3 } };
|
||||
auto* const n = QskSGNode::ensureNode< Node >( node );
|
||||
updateBoxNode( skinnable, n->firstChild(), rect, {}, {}, {}, g );
|
||||
updateTextNode( skinnable, n->lastChild(), rect, Qt::AlignTop | Qt::AlignLeft,
|
||||
"Reference", QskControl::Background );
|
||||
return n;
|
||||
}
|
||||
if ( nodeRole == B )
|
||||
{
|
||||
const auto rectB = rect.adjusted( 0, dy, 0, dy );
|
||||
auto* const n = QskSGNode::ensureNode< Node >( node );
|
||||
updateBoxNode(
|
||||
skinnable, n->firstChild(), rectB, {}, {}, {}, extracted( g, from, to ) );
|
||||
updateTextNode( skinnable, n->lastChild(), rectB, Qt::AlignTop | Qt::AlignLeft,
|
||||
"Expected", QskControl::Background );
|
||||
return n;
|
||||
}
|
||||
if ( nodeRole == C )
|
||||
{
|
||||
const auto rectC = rect.adjusted( 0, 2 * dy, 0, 2 * dy );
|
||||
auto* const n = QskSGNode::ensureNode< Node >( node );
|
||||
updateBoxNode( skinnable, n->firstChild(), rectC, {}, {}, {}, g.extracted( from, to ) );
|
||||
updateTextNode( skinnable, n->lastChild(), rectC, Qt::AlignTop | Qt::AlignLeft,
|
||||
"Actual", QskControl::Background );
|
||||
return n;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
#ifdef ITEM_STATISTICS
|
||||
QskObjectCounter counter( true );
|
||||
#endif
|
||||
|
||||
QGuiApplication app( argc, argv );
|
||||
|
||||
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
|
||||
|
||||
auto* const layout = new QskLinearBox(Qt::Vertical);
|
||||
auto* const row = new QskLinearBox(layout);
|
||||
auto* const control = new Control(layout);
|
||||
auto* const skinlet = new Skinlet;
|
||||
control->setSkinlet( skinlet );
|
||||
skinlet->setOwnedBySkinnable( true );
|
||||
|
||||
auto qskHGradient = [](Qt::Orientation orientation , QskGradient gradient ){
|
||||
gradient.setLinearDirection(orientation);
|
||||
return gradient;
|
||||
};
|
||||
|
||||
{
|
||||
auto* const button = new QskPushButton( row );
|
||||
button->setGradientHint(QskPushButton::Panel, Qt::red);
|
||||
QObject::connect(button, &QskPushButton::clicked, control, [control, button](){
|
||||
control->setGradientHint(Control::Gradient, button->gradientHint(QskPushButton::Panel));
|
||||
});
|
||||
}
|
||||
{
|
||||
auto* const button = new QskPushButton( row );
|
||||
button->setGradientHint(QskPushButton::Panel, qskHGradient(Qt::Horizontal, {Qt::red, Qt::green}));
|
||||
QObject::connect(button, &QskPushButton::clicked, control, [control, button](){
|
||||
control->setGradientHint(Control::Gradient, button->gradientHint(QskPushButton::Panel));
|
||||
});
|
||||
}
|
||||
{
|
||||
auto* const button = new QskPushButton( row );
|
||||
button->setGradientHint(QskPushButton::Panel, qskHGradient(Qt::Horizontal,{{{0.0, Qt::red}, {0.5, Qt::green}, {1.0, Qt::blue}}}));
|
||||
QObject::connect(button, &QskPushButton::clicked, control, [control, button](){
|
||||
control->setGradientHint(Control::Gradient, button->gradientHint(QskPushButton::Panel));
|
||||
});
|
||||
}
|
||||
|
||||
QskWindow window;
|
||||
window.addItem( layout );
|
||||
window.resize( 600, 600 );
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
// #include "moc_MainWindow.cpp"
|
Loading…
Reference in New Issue