QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskBoxShapeMetrics.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskBoxShapeMetrics.h"
7
8#include <qhashfunctions.h>
9#include <qvariant.h>
10
11#include <algorithm>
12
13static void qskRegisterBoxShapeMetrics()
14{
15 qRegisterMetaType< QskBoxShapeMetrics >();
16
17#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
18 QMetaType::registerEqualsComparator< QskBoxShapeMetrics >();
19#endif
20
21 QMetaType::registerConverter< int, QskBoxShapeMetrics >(
22 []( int radius ) { return QskBoxShapeMetrics( radius ); } );
23
24 QMetaType::registerConverter< qreal, QskBoxShapeMetrics >(
25 []( qreal radius ) { return QskBoxShapeMetrics( radius ); } );
26}
27
28Q_CONSTRUCTOR_FUNCTION( qskRegisterBoxShapeMetrics )
29
30static inline QSizeF qskInterpolatedSize(
31 const QSizeF& from, const QSizeF& to, qreal ratio )
32{
33 return from + ( to - from ) * ratio;
34}
35
36static inline qreal qskAbsoluted( qreal length, qreal percentage )
37{
38 // 100% means -> 0.5 of length
39 percentage = qBound( 0.0, percentage, 100.0 );
40 return percentage / 100.0 * 0.5 * length;
41}
42
43static inline void qskSetRadius( qreal rx, qreal ry, QSizeF& radius )
44{
45 radius.rwidth() = ( rx > 0.0 ) ? rx : 0.0;
46 radius.rheight() = ( ry > 0.0 ) ? ry : 0.0;
47}
48
49void QskBoxShapeMetrics::setRadius(
50 qreal topLeftX, qreal topLeftY,
51 qreal topRightX, qreal topRightY,
52 qreal bottomLeftX, qreal bottomLeftY,
53 qreal bottomRightX, qreal bottomRightY ) noexcept
54{
55 qskSetRadius( topLeftX, topLeftY, m_radii[ Qt::TopLeftCorner ] );
56 qskSetRadius( topRightX, topRightY, m_radii[ Qt::TopRightCorner ] );
57 qskSetRadius( bottomLeftX, bottomLeftY, m_radii[ Qt::BottomLeftCorner ] );
58 qskSetRadius( bottomRightX, bottomRightY, m_radii[ Qt::BottomRightCorner ] );
59}
60
61void QskBoxShapeMetrics::setRadius( Qt::Corner corner, qreal radiusX, qreal radiusY ) noexcept
62{
63 if ( ( corner >= Qt::TopLeftCorner ) && ( corner <= Qt::BottomRightCorner ) )
64 qskSetRadius( radiusX, radiusY, m_radii[ corner ] );
65}
66
67void QskBoxShapeMetrics::setTopLeft( const QSizeF& radius ) noexcept
68{
69 setRadius( Qt::TopLeftCorner, radius );
70}
71
72void QskBoxShapeMetrics::setTopRight( const QSizeF& radius ) noexcept
73{
74 setRadius( Qt::TopRightCorner, radius );
75}
76
77void QskBoxShapeMetrics::setBottomLeft( const QSizeF& radius ) noexcept
78{
79 setRadius( Qt::BottomLeftCorner, radius );
80}
81
82void QskBoxShapeMetrics::setBottomRight( const QSizeF& radius ) noexcept
83{
84 setRadius( Qt::BottomRightCorner, radius );
85}
86
87QskBoxShapeMetrics QskBoxShapeMetrics::toAbsolute( const QSizeF& size ) const noexcept
88{
89 if ( m_sizeMode != Qt::RelativeSize )
90 return *this;
91
92 if ( size.isEmpty() )
93 return QskBoxShapeMetrics();
94
95 QskBoxShapeMetrics shape = *this;
96 shape.m_sizeMode = Qt::AbsoluteSize;
97
98 for ( int i = 0; i < 4; i++ )
99 {
100 auto& radius = shape.m_radii[ i ];
101
102 if ( radius.isEmpty() )
103 {
104 radius.rheight() = radius.rwidth() = 0.0;
105 continue;
106 }
107
108 const qreal rx = qskAbsoluted( size.width(), radius.width() );
109 const qreal ry = qskAbsoluted( size.height(), radius.height() );
110
111 switch ( m_scalingMode )
112 {
113 case Symmetric:
114 {
115 radius.rheight() = radius.rwidth() = std::min( rx, ry );
116 break;
117 }
118 case SymmetricByMaximum:
119 {
120 radius.rheight() = radius.rwidth() = std::max( rx, ry );
121 break;
122 }
123 default:
124 {
125 const auto ratio = radius.height() / radius.width();
126
127 if ( ratio >= 1.0 )
128 {
129 radius.rwidth() = ry / ratio;
130 radius.rheight() = ry;
131 }
132 else
133 {
134 radius.rwidth() = rx;
135 radius.rheight() = rx * ratio;
136 }
137 }
138 }
139 }
140
141 return shape;
142}
143
144QskBoxShapeMetrics QskBoxShapeMetrics::interpolated(
145 const QskBoxShapeMetrics& to, qreal ratio ) const noexcept
146{
147 // what about m_aspectRatioMode != to.m_aspectRatioMode ???
148
149 if ( ( *this == to ) || ( m_sizeMode != to.m_sizeMode ) )
150 return to;
151
152 return QskBoxShapeMetrics(
153 qskInterpolatedSize( m_radii[ 0 ], to.m_radii[ 0 ], ratio ),
154 qskInterpolatedSize( m_radii[ 1 ], to.m_radii[ 1 ], ratio ),
155 qskInterpolatedSize( m_radii[ 2 ], to.m_radii[ 2 ], ratio ),
156 qskInterpolatedSize( m_radii[ 3 ], to.m_radii[ 3 ], ratio ),
157 to.m_sizeMode, to.m_scalingMode );
158}
159
160QVariant QskBoxShapeMetrics::interpolate(
161 const QskBoxShapeMetrics& from, const QskBoxShapeMetrics& to, qreal progress ) noexcept
162{
163 return QVariant::fromValue( from.interpolated( to, progress ) );
164}
165
166QskHashValue QskBoxShapeMetrics::hash( QskHashValue seed ) const noexcept
167{
168 auto hash = qHash( static_cast< int >( m_sizeMode ), seed );
169 return qHashBits( m_radii, sizeof( m_radii ), hash );
170}
171
172#ifndef QT_NO_DEBUG_STREAM
173
174#include <qdebug.h>
175
176QDebug operator<<( QDebug debug, const QskBoxShapeMetrics& metrics )
177{
178 QDebugStateSaver saver( debug );
179 debug.nospace();
180
181 debug << "BoxShape" << '(';
182 debug << metrics.sizeMode();
183
184 for ( int i = Qt::TopLeftCorner; i <= Qt::BottomRightCorner; i++ )
185 {
186 const QSizeF r = metrics.radius( static_cast< Qt::Corner >( i ) );
187 debug << "(" << r.width() << ',' << r.height() << ")";
188 }
189
190 debug << ')';
191
192 return debug;
193}
194
195#endif
196
197#include "moc_QskBoxShapeMetrics.cpp"