6#include "QskGradientStop.h"
7#include "QskRgbValue.h"
9#include <qhashfunctions.h>
15static void qskRegisterGradientStop()
17 qRegisterMetaType< QskGradientStop >();
19#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
20 QMetaType::registerEqualsComparator< QskGradientStop >();
24Q_CONSTRUCTOR_FUNCTION( qskRegisterGradientStop )
26void QskGradientStop::setPosition( qreal position )
noexcept
28 m_position = position;
31void QskGradientStop::setColor(
const QColor& color )
noexcept
36void QskGradientStop::setRgb( QRgb rgb )
noexcept
38 m_color = QColor::fromRgba( rgb );
41void QskGradientStop::setStop( qreal position,
const QColor& color )
noexcept
43 m_position = position;
47void QskGradientStop::setStop( qreal position, Qt::GlobalColor color )
noexcept
49 m_position = position;
53QskHashValue QskGradientStop::hash( QskHashValue seed )
const noexcept
55 auto hash = qHashBits( &m_position,
sizeof( m_position ), seed );
56 return qHashBits( &m_color,
sizeof( m_color ), hash );
59QColor QskGradientStop::interpolated(
62 if ( s1.color() == s2.color() )
68 if ( min->position() > max->position() )
69 std::swap( min, max );
71 if ( position <= min->position() )
74 if ( position >= max->position() )
77 const qreal r = ( position - min->position() ) / ( max->position() - min->position() );
78 return QskRgb::interpolated( min->color(), max->color(), r );
81#ifndef QT_NO_DEBUG_STREAM
87 QDebugStateSaver saver( debug );
90 debug << stop.position() <<
": ";
91 QskRgb::debugColor( debug, stop.color() );
98#include "moc_QskGradientStop.cpp"
102static inline QColor qskInterpolatedColor(
103 const QskGradientStops& stops,
int index1,
int index2, qreal position )
105 const auto max =
static_cast< int >( stops.count() ) - 1;
107 index1 = qBound( 0, index1, max );
108 index2 = qBound( 0, index2, max );
110 return QskGradientStop::interpolated( stops[ index1 ], stops[ index2 ], position );
113bool qskIsVisible(
const QskGradientStops& stops )
noexcept
115 for (
const auto& stop : stops )
117 const auto& c = stop.color();
118 if ( c.isValid() && c.alpha() > 0 )
125bool qskIsMonochrome(
const QskGradientStops& stops )
noexcept
127 for (
int i = 1; i < stops.size(); i++ )
129 if ( stops[ i ].color() != stops[ 0 ].color() )
136QskGradientStops qskTransparentGradientStops(
const QskGradientStops& stops, qreal ratio )
138 auto newStops = stops;
140 for (
auto& stop : newStops )
142 auto c = stop.color();
143 c.setAlpha( qRound( c.alpha() * ratio ) );
151QskGradientStops qskInterpolatedGradientStops(
152 const QskGradientStops& stops,
const QColor& color, qreal ratio )
154 auto newStops = stops;
156 for (
auto& stop : newStops )
157 stop.setColor( QskRgb::interpolated( stop.color(), color, ratio ) );
162QskGradientStops qskInterpolatedGradientStops(
163 const QColor& color,
const QskGradientStops& stops, qreal ratio )
165 auto newStops = stops;
167 for (
auto& stop : newStops )
168 stop.setColor( QskRgb::interpolated( color, stop.color(), ratio ) );
173static QskGradientStops qskInterpolatedStops(
174 const QskGradientStops& from,
const QskGradientStops& to, qreal ratio )
182 QVector< QskGradientStop > stops;
185 while ( ( i < from.count() ) || ( j < to.count() ) )
190 if ( i == from.count() )
192 c1 = from.last().color();
194 pos = to[j++].position();
196 else if ( j == to.count() )
198 c1 = from[i].color();
199 c2 = to.last().color();
200 pos = from[i++].position();
204 c1 = from[i].color();
207 const qreal dpos = from[i].position() - to[j].position();
209 if ( qFuzzyIsNull( dpos ) )
211 pos = from[i++].position();
214 else if ( dpos < 0.0 )
216 pos = from[i++].position();
220 const auto& stop = to[j - 1];
221 c2 = QskRgb::interpolated( stop.color(), c2, pos - stop.position() );
226 pos = to[j++].position();
230 const auto& stop = from[i - 1];
231 c1 = QskRgb::interpolated( stop.color(), c1, pos - stop.position() );
236 stops +=
QskGradientStop( pos, QskRgb::interpolated( c1, c2, ratio ) );
242QskGradientStops qskInterpolatedGradientStops(
243 const QskGradientStops& from,
bool fromIsMonochrome,
244 const QskGradientStops& to,
bool toIsMonochrome, qreal ratio )
246 if ( from.isEmpty() && to.isEmpty() )
247 return QskGradientStops();
249 if ( from.isEmpty() )
250 return qskTransparentGradientStops( to, ratio );
253 return qskTransparentGradientStops( from, 1.0 - ratio );
255 if ( fromIsMonochrome && toIsMonochrome )
257 const auto c = QskRgb::interpolated(
258 from[ 0 ].color(), to[ 0 ].color(), ratio );
260 return { { 0.0, c }, { 1.0, c } };
263 if ( fromIsMonochrome )
265 return qskInterpolatedGradientStops( from[ 0 ].color(), to, ratio );
268 if ( toIsMonochrome )
270 return qskInterpolatedGradientStops( from, to[ 0 ].color(), ratio );
273 return qskInterpolatedStops( from, to, ratio );
276QColor qskInterpolatedColorAt(
const QskGradientStops& stops, qreal pos )
noexcept
278 if ( stops.isEmpty() )
281 pos = qBound( 0.0, pos, 1.0 );
283 if ( pos <= stops.first().position() )
284 return stops.first().color();
286 for (
int i = 1; i < stops.count(); i++ )
288 if ( pos <= stops[i].position() )
289 return qskInterpolatedColor( stops, i - 1, i, pos );
292 return stops.last().color();
295QskGradientStops qskExtractedGradientStops(
296 const QskGradientStops& gradientStops, qreal from, qreal to )
298 if ( ( from > to ) || ( from > 1.0 ) || gradientStops.isEmpty() )
299 return QskGradientStops();
301 if ( ( from <= 0.0 ) && ( to >= 1.0 ) )
302 return gradientStops;
304 from = qMax( from, 0.0 );
305 to = qMin( to, 1.0 );
307 QVector< QskGradientStop > stops1 = gradientStops;
312 if ( stops1.first().position() > 0.0 )
315 if ( stops1.last().position() < 1.0 )
319 QVector< QskGradientStop > stops2;
320 stops2.reserve( stops1.count() );
322 if ( stops1.count() == 2 )
324 const auto rgb1 = stops1.first().rgb();
325 const auto rgb2 = stops1.last().rgb();
327 stops2 +=
QskGradientStop( 0.0, QskRgb::interpolated( rgb1, rgb2, from ) );
328 stops2 +=
QskGradientStop( 1.0, QskRgb::interpolated( rgb1, rgb2, to ) );
334 for ( ; i < stops1.count(); i++ )
336 if ( stops1[i].position() > from )
341 qskInterpolatedColor( stops1, i - 1, i, from ) );
343 for ( ; i < stops1.count(); i++ )
345 if ( stops1[i].position() >= to )
348 const auto pos = ( stops1[i].position() - from ) / ( to - from );
353 qskInterpolatedColor( stops1, i, i + 1, to ) );
359QskGradientStops qskRevertedGradientStops(
const QskGradientStops& stops )
361 QVector< QskGradientStop > s;
362 s.reserve( stops.count() );
364 for (
auto it = stops.crbegin(); it != stops.crend(); ++it )
370QVector< QskGradientStop > qskBuildGradientStops(
const QGradientStops& qtStops )
372 QVector< QskGradientStop > stops;
373 stops.reserve( qtStops.count() );
375 for (
const auto& s : qtStops )
381template<
typename T >
382static inline QVector< QskGradientStop > qskCreateStops(
383 const QVector< T > colors,
bool discrete )
385 QVector< QskGradientStop > stops;
387 const auto count = colors.count();
403 const auto step = 1.0 / count;
404 stops.reserve( 2 * count - 2 );
408 for (
int i = 1; i < count; i++ )
410 const qreal pos = i * step;
419 const auto step = 1.0 / ( count - 1 );
420 stops.reserve( count );
424 for (
int i = 1; i < count - 1; i++ )
433QskGradientStops qskBuildGradientStops(
const QVector< QRgb >& colors,
bool discrete )
435 return qskCreateStops( colors, discrete );
438QskGradientStops qskBuildGradientStops(
const QVector< QColor >& colors,
bool discrete )
440 return qskCreateStops( colors, discrete );
443QGradientStops qskToQGradientStops(
const QskGradientStops& stops )
445 QGradientStops qStops;
446 qStops.reserve( stops.count() );
448 for (
const auto& stop : stops )
450 QPair< qreal, QColor > qStop = { stop.position(), stop.color() };
452 if ( !qStops.isEmpty() && qStops.last().first == qStop.first )
458 qStop.first = qMin( qStop.first + 0.00001, 1.0 );