Compare commits

...

8 Commits

Author SHA1 Message Date
Uwe Rathmann 7acd0f9c63 more operations for QskGradientStops 2025-05-15 11:25:49 +02:00
Peter Hartmann 824c2673a7
shaders: Use different names for qt6_add_shaders calls (#517)
Otherwise it won't work for WAsm.
According to the doc: "The name after the project has to be unique
for each call."
2025-05-07 16:48:41 +02:00
Uwe Rathmann 8f89e38ec3 QskGradientStops code internally reorganized for planned new features 2025-05-06 16:21:52 +02:00
Uwe Rathmann dd5c97a077 QskGradientStop interpolation formalized 2025-05-06 10:59:15 +02:00
Peter Hartmann cf8a45fb08
tab bar: Take scroll position into account when making item visible (#513)
If the tab bar is scrolled, the position we get from calling
mapFromItem() is less than the real position with a scrolling of 0,
because mapFromItem() does not know about our scroll position.

This is usually not noticed when creating a tab bar, because the
scroll position is (0,0). When calling this method on a scrolled
tab bar, the problem becomes visible.
2025-05-04 12:01:08 +02:00
Peter Hartmann a10e4a244d
CI: Let install-qt choose the python version (#514) 2025-05-04 10:14:17 +02:00
Uwe Rathmann a10a0a9958 some docs added 2025-03-31 18:11:09 +02:00
Uwe Rathmann 1d6a1348ef avoid compiler warnings 2025-03-31 16:40:52 +02:00
11 changed files with 216 additions and 86 deletions

View File

@ -202,7 +202,6 @@ jobs:
install-deps: "true"
modules: "qtwebengine"
cached: ${{ steps.cache-qt-5-15.outputs.cache-hit }}
setup-python: "false"
tools: ""
set-env: "true"
tools-only: "false"
@ -216,7 +215,6 @@ jobs:
install-deps: "true"
modules: "qtwebengine qtshadertools"
cached: ${{ steps.cache-qt-6-2.outputs.cache-hit }}
setup-python: "false"
tools: ""
set-env: "true"
tools-only: "false"

View File

@ -149,7 +149,7 @@ function(qsk_add_example target)
endfunction()
function(qsk_add_shaders target)
function(qsk_add_shaders target shader_name)
cmake_parse_arguments( arg "" "" "FILES" ${ARGN} )
@ -160,7 +160,7 @@ function(qsk_add_shaders target)
list(APPEND outfiles "${qsbname}.qsb")
endforeach()
qt6_add_shaders( ${target} "qskshaders" BATCHABLE PRECOMPILE QUIET
qt6_add_shaders( ${target} ${shader_name} BATCHABLE PRECOMPILE QUIET
PREFIX "/qskinny/shaders" ${ARGV} OUTPUTS ${outfiles} )
# pass on OUTPUT_TARGETS to the caller of this function

View File

@ -35,6 +35,6 @@ if (QT_VERSION_MAJOR VERSION_GREATER_EQUAL 6)
shaders/arcshadow-vulkan.vert
shaders/arcshadow-vulkan.frag
)
qsk_add_shaders( ${target} FILES ${SHADERS} OUTPUT_TARGETS shader_target)
qsk_add_shaders( ${target} "qskArcShaders" FILES ${SHADERS} OUTPUT_TARGETS shader_target)
endif()

View File

@ -510,7 +510,7 @@ else()
endif()
if (QT_VERSION_MAJOR VERSION_GREATER_EQUAL 6)
qsk_add_shaders( ${target} FILES ${SHADERS} OUTPUT_TARGETS shader_target)
qsk_add_shaders( ${target} "qskshaders" FILES ${SHADERS} OUTPUT_TARGETS shader_target)
endif()
target_include_directories(${target} PUBLIC

View File

@ -81,7 +81,7 @@ QskGradient::QskGradient( const QColor& color1, const QColor& color2 )
QskGradient::QskGradient( QGradient::Preset preset )
: QskGradient()
{
setStops( qskBuildGradientStops( QGradient( preset ).stops() ) );
setStops( qskFromQGradientStops( QGradient( preset ).stops() ) );
}
QskGradient::QskGradient( const QVector< QskGradientStop >& stops )
@ -165,7 +165,7 @@ QskGradient::QskGradient( const QGradient& qGradient )
}
}
setStops( qskBuildGradientStops( qGradient.stops() ) );
setStops( qskFromQGradientStops( qGradient.stops() ) );
}
QskGradient::QskGradient( const QskGradient& other ) noexcept
@ -305,7 +305,7 @@ void QskGradient::setStops( const QColor& color1, const QColor& color2 )
void QskGradient::setStops( QGradient::Preset preset )
{
const auto stops = qskBuildGradientStops( QGradient( preset ).stops() );
const auto stops = qskFromQGradientStops( QGradient( preset ).stops() );
setStops( stops );
}

View File

@ -23,6 +23,31 @@ static void qskRegisterGradientStop()
Q_CONSTRUCTOR_FUNCTION( qskRegisterGradientStop )
static inline qreal qskBoundedStopPos( qreal pos )
{
if ( ( pos < 0.0 ) || qFuzzyIsNull( pos ) )
return 0.0;
if ( ( pos > 1.0 ) || qFuzzyCompare( pos, 1.0 ) )
return 1.0;
return pos;
}
static inline QVector< QskGradientStop >
qskNormalizedStops( const QVector< QskGradientStop >& stops )
{
auto s = stops;
if ( s.first().position() > 0.0 )
s.prepend( QskGradientStop( 0.0, s.first().color() ) );
if ( s.last().position() < 1.0 )
s.append( QskGradientStop( 1.0, s.last().color() ) );
return s;
}
void QskGradientStop::setPosition( qreal position ) noexcept
{
m_position = position;
@ -56,26 +81,19 @@ QskHashValue QskGradientStop::hash( QskHashValue seed ) const noexcept
return qHashBits( &m_color, sizeof( m_color ), hash );
}
QColor QskGradientStop::interpolated(
const QskGradientStop& s1, const QskGradientStop& s2, qreal position ) noexcept
QskGradientStop QskGradientStop::interpolated(
const QskGradientStop& to, qreal ratio ) const
{
if ( s1.color() == s2.color() )
return s1.color();
return QskGradientStop(
m_position + ( to.m_position - m_position ) * ratio,
QskRgb::interpolated( m_color, to.m_color, ratio )
);
}
auto min = &s1;
auto max = &s2;
if ( min->position() > max->position() )
std::swap( min, max );
if ( position <= min->position() )
return min->color();
if ( position >= max->position() )
return max->color();
const qreal r = ( position - min->position() ) / ( max->position() - min->position() );
return QskRgb::interpolated( min->color(), max->color(), r );
QVariant QskGradientStop::interpolate(
const QskGradientStop& from, const QskGradientStop& to, qreal ratio )
{
return QVariant::fromValue( from.interpolated( to, ratio ) );
}
#ifndef QT_NO_DEBUG_STREAM
@ -95,19 +113,23 @@ QDebug operator<<( QDebug debug, const QskGradientStop& stop )
#endif
#include "moc_QskGradientStop.cpp"
// some helper functions around QskGradientStops
static inline QColor qskInterpolatedColor(
const QskGradientStops& stops, int index1, int index2, qreal position )
static inline QColor qskColorAtPosition(
const QskGradientStop& s1, const QskGradientStop& s2, qreal pos )
{
const auto max = static_cast< int >( stops.count() ) - 1;
const auto dp = s2.position() - s1.position();
if ( qFuzzyIsNull( dp ) )
return s1.color();
index1 = qBound( 0, index1, max );
index2 = qBound( 0, index2, max );
return QskRgb::interpolated(
s1.color(), s2.color(), ( pos - s1.position() ) / dp );
}
return QskGradientStop::interpolated( stops[ index1 ], stops[ index2 ], position );
static inline QskGradientStop qskCreateStopAtPosition(
const QskGradientStop& s1, const QskGradientStop& s2, qreal pos )
{
return { pos, qskColorAtPosition( s1, s2, pos ) };
}
bool qskIsVisible( const QskGradientStops& stops ) noexcept
@ -278,43 +300,126 @@ QColor qskInterpolatedColorAt( const QskGradientStops& stops, qreal pos ) noexce
if ( stops.isEmpty() )
return QColor();
pos = qBound( 0.0, pos, 1.0 );
if ( pos <= stops.first().position() )
return stops.first().color();
for ( int i = 1; i < stops.count(); i++ )
{
if ( pos <= stops[i].position() )
return qskInterpolatedColor( stops, i - 1, i, pos );
if ( pos <= stops[ i ].position() )
return qskColorAtPosition( stops[ i - 1 ], stops[ i ], pos );
}
return stops.last().color();
}
QskGradientStops qskExtractedGradientStops(
const QskGradientStops& gradientStops, qreal from, qreal to )
QskGradientStops qskReplacedGradientStops( const QskGradientStops& gradientStops,
const QskGradientStop& stop1, const QskGradientStop& stop2 )
{
if ( ( from > to ) || ( from > 1.0 ) || gradientStops.isEmpty() )
return QskGradientStops();
if ( ( from <= 0.0 ) && ( to >= 1.0 ) )
if ( stop1.position() >= stop2.position() )
return gradientStops;
from = qMax( from, 0.0 );
to = qMin( to, 1.0 );
const auto s1 = QskGradientStop( qskBoundedStopPos( stop1.position() ), stop1.color() );
const auto s2 = QskGradientStop( qskBoundedStopPos( stop2.position() ), stop2.color() );
QVector< QskGradientStop > stops1 = gradientStops;
QskGradientStops stops;
#if 1
// not the most efficient implementation - maybe later TODO ...
if ( s1.position() == 0.0 && s2.position() == 1.0 )
{
stops = { s1, s2 };
}
else if ( qskIsMonochrome( gradientStops ) )
{
stops.reserve( 4 );
if ( stops1.first().position() > 0.0 )
stops1.prepend( QskGradientStop( 0.0, stops1.first().color() ) );
const auto c = gradientStops.isEmpty()
? QColor::fromRgba( 0 ) : gradientStops.first().color();
if ( stops1.last().position() < 1.0 )
stops1.append( QskGradientStop( 1.0, stops1.last().color() ) );
#endif
if ( s1.position() > 0.0 )
stops += { s1.position(), c };
stops += s1;
stops += s2;
if ( s2.position() < 1.0 )
stops += { s2.position(), c };
}
else
{
// not the most efficient implementation - maybe later TODO ...
const auto stops0 = qskNormalizedStops( gradientStops );
int i = 0;
if ( s1.position() > 0.0 )
{
while ( s1.position() > stops0[i].position() )
stops += stops0[i++];
if ( s1.position() == stops0[i].position() )
stops += stops0[i++];
else
stops += qskCreateStopAtPosition( stops0[i - 1], stops0[i], s1.position() );
}
stops += s1;
while ( s2.position() > stops0[i].position() )
i++;
stops += s2;
if ( s2.position() < 1.0 )
{
while ( stops0[i + 1].position() == s2.position() )
i++;
if ( s2.position() != stops0[i].position() )
stops += qskCreateStopAtPosition( stops0[i - 1], stops0[i], s2.position() );
while( i < stops0.count() )
stops += stops0[i++];
}
}
return stops;
}
QskGradientStops qskClippedGradientStops(
const QskGradientStops& stops, qreal from, qreal to )
{
return qskReplacedGradientStops( stops, { from, 0 }, { to, 0 } );
}
QskGradientStops qskExtractedGradientStops(
const QskGradientStops& stops, qreal from, qreal to )
{
if ( ( from > to ) || ( to > 1.0 ) || ( from < 0.0 ) || stops.isEmpty() )
return QskGradientStops();
from = qskBoundedStopPos( from );
to = qskBoundedStopPos( to );
if ( ( from == 0.0 ) && ( to == 1.0 ) )
return stops;
if ( from == to )
{
const auto color = qskInterpolatedColorAt( stops, from );
QVector< QskGradientStop > s;
s.reserve( 2 );
s += QskGradientStop( 0.0, color );
s += QskGradientStop( 1.0, color );
return s;
}
/*
For situations where we have no stops at 0.0 and 1.0 we insert them
manually. Not the most efficient implementation, but we avoid having
to deal with these situations for the moment. TODO ...
*/
const auto stops1 = qskNormalizedStops( stops );
QVector< QskGradientStop > stops2;
stops2.reserve( stops1.count() );
@ -331,26 +436,26 @@ QskGradientStops qskExtractedGradientStops(
{
int i = 0;
for ( ; i < stops1.count(); i++ )
if ( from == 0.0 )
{
if ( stops1[i].position() > from )
break;
stops2 += stops1[i++];
}
else
{
while( stops1[++i].position() <= from ); // skip leading stops
stops2 += QskGradientStop( 0.0,
qskColorAtPosition( stops1[i - 1], stops1[ i ], from ) );
}
stops2 += QskGradientStop( 0.0,
qskInterpolatedColor( stops1, i - 1, i, from ) );
for ( ; i < stops1.count(); i++ )
while ( stops1[i].position() < to )
{
if ( stops1[i].position() >= to )
break;
const auto pos = ( stops1[i].position() - from ) / ( to - from );
stops2 += QskGradientStop( pos, stops1[i].color() );
stops2 += QskGradientStop( pos, stops1[i++].color() );
}
stops2 += QskGradientStop( 1.0,
qskInterpolatedColor( stops1, i, i + 1, to ) );
qskColorAtPosition( stops1[i - 1], stops1[ i ], to ) );
}
return stops2;
@ -367,7 +472,7 @@ QskGradientStops qskRevertedGradientStops( const QskGradientStops& stops )
return s;
}
QVector< QskGradientStop > qskBuildGradientStops( const QGradientStops& qtStops )
QVector< QskGradientStop > qskFromQGradientStops( const QGradientStops& qtStops )
{
QVector< QskGradientStop > stops;
stops.reserve( qtStops.count() );
@ -463,3 +568,5 @@ QGradientStops qskToQGradientStops( const QskGradientStops& stops )
return qStops;
}
#include "moc_QskGradientStop.cpp"

View File

@ -45,8 +45,10 @@ class QSK_EXPORT QskGradientStop
void setRgb( QRgb ) noexcept;
QRgb rgb() const noexcept;
static QColor interpolated(
const QskGradientStop&, const QskGradientStop&, qreal position ) noexcept;
QskGradientStop interpolated( const QskGradientStop&, qreal ) const;
static QVariant interpolate( const QskGradientStop&,
const QskGradientStop&, qreal );
QskHashValue hash( QskHashValue seed ) const noexcept;
@ -129,27 +131,48 @@ QSK_EXPORT QskGradientStops qskInterpolatedGradientStops(
const QskGradientStops&, bool, const QskGradientStops&, bool,
qreal ratio );
// interpolating colors in direction of a color.
QSK_EXPORT QskGradientStops qskInterpolatedGradientStops(
const QskGradientStops&, const QColor&, qreal ratio );
// interpolating colors starting from a color.
QSK_EXPORT QskGradientStops qskInterpolatedGradientStops(
const QColor&, const QskGradientStops&, qreal ratio );
// interpolating the opacity of the colors
QSK_EXPORT QskGradientStops qskTransparentGradientStops(
const QskGradientStops&, qreal ratio );
// extracting the colors of [from, to ] and stretching them to [0.0, 1.0]
QSK_EXPORT QskGradientStops qskExtractedGradientStops(
const QskGradientStops&, qreal from, qreal to );
// reverting the color stops
QSK_EXPORT QskGradientStops qskRevertedGradientStops( const QskGradientStops& );
QSK_EXPORT QskGradientStops qskReplacedGradientStops(
const QskGradientStops&, const QskGradientStop&, const QskGradientStop& );
QSK_EXPORT QskGradientStops qskClippedGradientStops(
const QskGradientStops&, qreal from, qreal to );
/*
creating equidistant color stops from a list of colors.
when discrete is true the result will contain 2 stops at each position
one with the previous and one with the following color so that the
interval [pos1-pos2] will be monochrome.
*/
QSK_EXPORT QskGradientStops qskBuildGradientStops(
const QVector< QRgb >&, bool discrete = false );
QSK_EXPORT QskGradientStops qskBuildGradientStops(
const QVector< QColor >&, bool discrete = false );
QSK_EXPORT QskGradientStops qskRevertedGradientStops( const QskGradientStops& );
QSK_EXPORT QskGradientStops qskBuildGradientStops( const QVector< QGradientStop >& );
/*
convert color stops from/to a vector of QGradientStop, that can be
used for QGradients.
*/
QSK_EXPORT QskGradientStops qskFromQGradientStops( const QVector< QGradientStop >& );
QSK_EXPORT QVector< QGradientStop > qskToQGradientStops( const QVector< QskGradientStop >& );
#endif

View File

@ -41,7 +41,7 @@ class QSK_EXPORT QskTextColors
void setLinkColor( QRgb );
void setLinkColor( Qt::GlobalColor );
QskTextColors interpolated( const QskTextColors&, qreal value ) const;
QskTextColors interpolated( const QskTextColors&, qreal ratio ) const;
static QVariant interpolate( const QskTextColors&,
const QskTextColors&, qreal ratio );

View File

@ -129,7 +129,7 @@ namespace
{
if ( qskIsAncestorOf( this, item ) )
{
const auto pos = mapFromItem( item, QPointF() );
const auto pos = mapFromItem( item, QPointF() ) + scrollPos();
ensureVisible( QRectF( pos.x(), pos.y(), item->width(), item->height() ) );
}
}

View File

@ -13,6 +13,7 @@
#include "QskGraduationMetrics.h"
#include "QskColorFilter.h"
#include "QskGradient.h"
#include "QskGradientStop.h"
#include "QskMargins.h"
#include "QskIntervalF.h"
#include "QskTextColors.h"
@ -43,6 +44,7 @@ static void qskRegisterInterpolator()
qRegisterAnimationInterpolator< QskColorFilter >( QskColorFilter::interpolate );
qRegisterAnimationInterpolator< QskIntervalF >( QskIntervalF::interpolate );
qRegisterAnimationInterpolator< QskMargins >( QskMargins::interpolate );
qRegisterAnimationInterpolator< QskGradientStop >( QskGradientStop::interpolate );
qRegisterAnimationInterpolator< QskGradient >( QskGradient::interpolate );
qRegisterAnimationInterpolator< QskBoxShapeMetrics >( QskBoxShapeMetrics::interpolate );
qRegisterAnimationInterpolator< QskBoxBorderMetrics >( QskBoxBorderMetrics::interpolate );

View File

@ -54,16 +54,16 @@ namespace
}
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
// make Qt 5/6 APIs matching
QSGMaterialShader* createShader(
QSGRendererInterface::RenderMode ) const override final
#else
QSGMaterialShader* createShader() const override final
#endif
{
return createShader();
return createMaterialShader();
}
virtual QSGMaterialShader* createShader() const = 0;
#endif
virtual QSGMaterialShader* createMaterialShader() const = 0;
virtual bool setGradient( const QskGradient& ) = 0;
};
@ -217,7 +217,7 @@ namespace
return GradientMaterial::compare( other );
}
QSGMaterialShader* createShader() const override;
QSGMaterialShader* createMaterialShader() const override;
/*
xy: position
@ -299,7 +299,7 @@ namespace
};
#endif
QSGMaterialShader* LinearMaterial::createShader() const
QSGMaterialShader* LinearMaterial::createMaterialShader() const
{
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
if ( !( flags() & QSGMaterial::RhiShaderWanted ) )
@ -371,7 +371,7 @@ namespace
}
}
QSGMaterialShader* createShader() const override;
QSGMaterialShader* createMaterialShader() const override;
QVector2D m_center;
QVector2D m_radius;
@ -465,7 +465,7 @@ namespace
};
#endif
QSGMaterialShader* RadialMaterial::createShader() const
QSGMaterialShader* RadialMaterial::createMaterialShader() const
{
#ifdef SHADER_GL
if ( !( flags() & QSGMaterial::RhiShaderWanted ) )
@ -575,7 +575,7 @@ namespace
return GradientMaterial::compare( other );
}
QSGMaterialShader* createShader() const override;
QSGMaterialShader* createMaterialShader() const override;
QVector2D m_center;
float m_aspectRatio = 1.0;
@ -685,7 +685,7 @@ namespace
};
#endif
QSGMaterialShader* ConicMaterial::createShader() const
QSGMaterialShader* ConicMaterial::createMaterialShader() const
{
#ifdef SHADER_GL
if ( !( flags() & QSGMaterial::RhiShaderWanted ) )