/****************************************************************************** * QSkinny - Copyright (C) The authors * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ #include "QskBoxShapeMetrics.h" #include #include #include static void qskRegisterBoxShapeMetrics() { qRegisterMetaType< QskBoxShapeMetrics >(); #if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) QMetaType::registerEqualsComparator< QskBoxShapeMetrics >(); #endif QMetaType::registerConverter< int, QskBoxShapeMetrics >( []( int radius ) { return QskBoxShapeMetrics( radius ); } ); QMetaType::registerConverter< qreal, QskBoxShapeMetrics >( []( qreal radius ) { return QskBoxShapeMetrics( radius ); } ); } Q_CONSTRUCTOR_FUNCTION( qskRegisterBoxShapeMetrics ) static inline QSizeF qskInterpolatedSize( const QSizeF& from, const QSizeF& to, qreal ratio ) { return from + ( to - from ) * ratio; } static inline qreal qskAbsoluted( qreal length, qreal percentage ) { // 100% means -> 0.5 of length percentage = qBound( 0.0, percentage, 100.0 ); return percentage / 100.0 * 0.5 * length; } static inline void qskSetRadius( qreal rx, qreal ry, QSizeF& radius ) { radius.rwidth() = ( rx > 0.0 ) ? rx : 0.0; radius.rheight() = ( ry > 0.0 ) ? ry : 0.0; } void QskBoxShapeMetrics::setRadius( qreal topLeftX, qreal topLeftY, qreal topRightX, qreal topRightY, qreal bottomLeftX, qreal bottomLeftY, qreal bottomRightX, qreal bottomRightY ) noexcept { qskSetRadius( topLeftX, topLeftY, m_radii[ Qt::TopLeftCorner ] ); qskSetRadius( topRightX, topRightY, m_radii[ Qt::TopRightCorner ] ); qskSetRadius( bottomLeftX, bottomLeftY, m_radii[ Qt::BottomLeftCorner ] ); qskSetRadius( bottomRightX, bottomRightY, m_radii[ Qt::BottomRightCorner ] ); } void QskBoxShapeMetrics::setRadius( Qt::Corner corner, qreal radiusX, qreal radiusY ) noexcept { if ( ( corner >= Qt::TopLeftCorner ) && ( corner <= Qt::BottomRightCorner ) ) qskSetRadius( radiusX, radiusY, m_radii[ corner ] ); } void QskBoxShapeMetrics::setTopLeft( const QSizeF& radius ) noexcept { setRadius( Qt::TopLeftCorner, radius ); } void QskBoxShapeMetrics::setTopRight( const QSizeF& radius ) noexcept { setRadius( Qt::TopRightCorner, radius ); } void QskBoxShapeMetrics::setBottomLeft( const QSizeF& radius ) noexcept { setRadius( Qt::BottomLeftCorner, radius ); } void QskBoxShapeMetrics::setBottomRight( const QSizeF& radius ) noexcept { setRadius( Qt::BottomRightCorner, radius ); } QskBoxShapeMetrics QskBoxShapeMetrics::toAbsolute( const QSizeF& size ) const noexcept { if ( m_sizeMode != Qt::RelativeSize ) return *this; if ( size.isEmpty() ) return QskBoxShapeMetrics(); QskBoxShapeMetrics shape = *this; shape.m_sizeMode = Qt::AbsoluteSize; for ( int i = 0; i < 4; i++ ) { auto& radius = shape.m_radii[ i ]; if ( radius.isEmpty() ) { radius.rheight() = radius.rwidth() = 0.0; continue; } const qreal rx = qskAbsoluted( size.width(), radius.width() ); const qreal ry = qskAbsoluted( size.height(), radius.height() ); switch ( m_scalingMode ) { case Symmetric: { radius.rheight() = radius.rwidth() = std::min( rx, ry ); break; } case SymmetricByMaximum: { radius.rheight() = radius.rwidth() = std::max( rx, ry ); break; } default: { const auto ratio = radius.height() / radius.width(); if ( ratio >= 1.0 ) { radius.rwidth() = ry / ratio; radius.rheight() = ry; } else { radius.rwidth() = rx; radius.rheight() = rx * ratio; } } } } return shape; } QskBoxShapeMetrics QskBoxShapeMetrics::interpolated( const QskBoxShapeMetrics& to, qreal ratio ) const noexcept { // what about m_aspectRatioMode != to.m_aspectRatioMode ??? if ( ( *this == to ) || ( m_sizeMode != to.m_sizeMode ) ) return to; return QskBoxShapeMetrics( qskInterpolatedSize( m_radii[ 0 ], to.m_radii[ 0 ], ratio ), qskInterpolatedSize( m_radii[ 1 ], to.m_radii[ 1 ], ratio ), qskInterpolatedSize( m_radii[ 2 ], to.m_radii[ 2 ], ratio ), qskInterpolatedSize( m_radii[ 3 ], to.m_radii[ 3 ], ratio ), to.m_sizeMode, to.m_scalingMode ); } QVariant QskBoxShapeMetrics::interpolate( const QskBoxShapeMetrics& from, const QskBoxShapeMetrics& to, qreal progress ) noexcept { return QVariant::fromValue( from.interpolated( to, progress ) ); } QskHashValue QskBoxShapeMetrics::hash( QskHashValue seed ) const noexcept { auto hash = qHash( static_cast< int >( m_sizeMode ), seed ); return qHashBits( m_radii, sizeof( m_radii ), hash ); } #ifndef QT_NO_DEBUG_STREAM #include QDebug operator<<( QDebug debug, const QskBoxShapeMetrics& metrics ) { QDebugStateSaver saver( debug ); debug.nospace(); debug << "BoxShape" << '('; debug << metrics.sizeMode(); for ( int i = Qt::TopLeftCorner; i <= Qt::BottomRightCorner; i++ ) { const QSizeF r = metrics.radius( static_cast< Qt::Corner >( i ) ); debug << "(" << r.width() << ',' << r.height() << ")"; } debug << ')'; return debug; } #endif #include "moc_QskBoxShapeMetrics.cpp"