File indexing completed on 2024-05-19 04:25:04
0001 /* 0002 * SPDX-FileCopyrightText: 2000 Matthias Elter <elter@kde.org> 0003 * SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org> 0004 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 #ifndef KISGLOBAL_H_ 0009 #define KISGLOBAL_H_ 0010 0011 #include <limits> 0012 0013 #include <KoConfig.h> 0014 #include "kis_assert.h" 0015 0016 #include <QPoint> 0017 #include <QPointF> 0018 0019 const quint8 quint8_MAX = std::numeric_limits<quint8>::max(); 0020 const quint16 quint16_MAX = std::numeric_limits<quint16>::max(); 0021 0022 const qint16 qint16_MIN = std::numeric_limits<qint16>::min(); 0023 const qint16 qint16_MAX = std::numeric_limits<qint16>::max(); 0024 const qint32 qint32_MAX = std::numeric_limits<qint32>::max(); 0025 const qint32 qint32_MIN = std::numeric_limits<qint32>::min(); 0026 0027 const quint8 MAX_SELECTED = std::numeric_limits<quint8>::max(); 0028 const quint8 MIN_SELECTED = std::numeric_limits<quint8>::min(); 0029 const quint8 SELECTION_THRESHOLD = 1; 0030 0031 enum OutlineStyle { 0032 OUTLINE_NONE = 0, 0033 OUTLINE_CIRCLE, 0034 OUTLINE_FULL, 0035 OUTLINE_TILT, 0036 0037 N_OUTLINE_STYLE_SIZE 0038 }; 0039 0040 enum CursorStyle { 0041 CURSOR_STYLE_NO_CURSOR = 0, 0042 CURSOR_STYLE_TOOLICON, 0043 CURSOR_STYLE_POINTER, 0044 CURSOR_STYLE_SMALL_ROUND, 0045 CURSOR_STYLE_CROSSHAIR, 0046 CURSOR_STYLE_TRIANGLE_RIGHTHANDED, 0047 CURSOR_STYLE_TRIANGLE_LEFTHANDED, 0048 CURSOR_STYLE_BLACK_PIXEL, 0049 CURSOR_STYLE_WHITE_PIXEL, 0050 CURSOR_STYLE_ERASER, 0051 0052 N_CURSOR_STYLE_SIZE 0053 }; 0054 0055 enum OldCursorStyle { 0056 OLD_CURSOR_STYLE_TOOLICON = 0, 0057 OLD_CURSOR_STYLE_CROSSHAIR = 1, 0058 OLD_CURSOR_STYLE_POINTER = 2, 0059 0060 OLD_CURSOR_STYLE_OUTLINE = 3, 0061 0062 OLD_CURSOR_STYLE_NO_CURSOR = 4, 0063 OLD_CURSOR_STYLE_SMALL_ROUND = 5, 0064 0065 OLD_CURSOR_STYLE_OUTLINE_CENTER_DOT = 6, 0066 OLD_CURSOR_STYLE_OUTLINE_CENTER_CROSS = 7, 0067 0068 OLD_CURSOR_STYLE_TRIANGLE_RIGHTHANDED = 8, 0069 OLD_CURSOR_STYLE_TRIANGLE_LEFTHANDED = 9, 0070 0071 OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_RIGHTHANDED = 10, 0072 OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_LEFTHANDED = 11 0073 }; 0074 0075 const double PRESSURE_MIN = 0.0; 0076 const double PRESSURE_MAX = 1.0; 0077 const double PRESSURE_DEFAULT = PRESSURE_MAX; 0078 const double PRESSURE_THRESHOLD = 5.0 / 255.0; 0079 0080 // copy of lcms.h 0081 #define INTENT_PERCEPTUAL 0 0082 #define INTENT_RELATIVE_COLORIMETRIC 1 0083 #define INTENT_SATURATION 2 0084 #define INTENT_ABSOLUTE_COLORIMETRIC 3 0085 0086 #include <cmath> 0087 0088 #ifndef M_PI 0089 #define M_PI 3.14159265358979323846 0090 #endif 0091 0092 // Name of the property in the KisApplication that contains the name 0093 // of the current style, even if there is a stylesheet applied 0094 constexpr const char *currentUnderlyingStyleNameProperty = "currentUnderlyingStyleName"; 0095 0096 // converts \p a to [0, 2 * M_PI) range 0097 template<typename T> 0098 typename std::enable_if<std::is_floating_point<T>::value, T>::type 0099 normalizeAngle(T a) { 0100 if (a < T(0.0)) { 0101 a = T(2 * M_PI) + std::fmod(a, T(2 * M_PI)); 0102 } 0103 0104 return a >= T(2 * M_PI) ? std::fmod(a, T(2 * M_PI)) : a; 0105 } 0106 0107 // converts \p a to [0, 360.0) range 0108 template<typename T> 0109 typename std::enable_if<std::is_floating_point<T>::value, T>::type 0110 normalizeAngleDegrees(T a) { 0111 if (a < T(0.0)) { 0112 a = T(360.0) + std::fmod(a, T(360.0)); 0113 } 0114 0115 return a >= T(360.0) ? std::fmod(a, T(360.0)) : a; 0116 } 0117 0118 inline qreal shortestAngularDistance(qreal a, qreal b) { 0119 qreal dist = fmod(qAbs(a - b), 2 * M_PI); 0120 if (dist > M_PI) dist = 2 * M_PI - dist; 0121 0122 return dist; 0123 } 0124 0125 inline qreal incrementInDirection(qreal a, qreal inc, qreal direction) { 0126 qreal b1 = a + inc; 0127 qreal b2 = a - inc; 0128 0129 qreal d1 = shortestAngularDistance(b1, direction); 0130 qreal d2 = shortestAngularDistance(b2, direction); 0131 0132 return d1 < d2 ? b1 : b2; 0133 } 0134 0135 inline qreal bisectorAngle(qreal a, qreal b) { 0136 const qreal diff = shortestAngularDistance(a, b); 0137 return incrementInDirection(a, 0.5 * diff, b); 0138 } 0139 0140 0141 0142 0143 template<typename T> 0144 inline T pow2(const T& x) { 0145 return x * x; 0146 } 0147 0148 template<typename T> 0149 inline T pow3(const T& x) { 0150 return x * x * x; 0151 } 0152 0153 template<typename T> 0154 inline T kisDegreesToRadians(T degrees) { 0155 return degrees * M_PI / 180.0; 0156 } 0157 0158 template<typename T> 0159 inline T kisRadiansToDegrees(T radians) { 0160 return radians * 180.0 / M_PI; 0161 } 0162 0163 template<class T, typename U> 0164 inline T kisGrowRect(const T &rect, U offset) { 0165 return rect.adjusted(-offset, -offset, offset, offset); 0166 } 0167 0168 inline qreal kisDistance(const QPointF &pt1, const QPointF &pt2) { 0169 return std::sqrt(pow2(pt1.x() - pt2.x()) + pow2(pt1.y() - pt2.y())); 0170 } 0171 0172 inline qreal kisSquareDistance(const QPointF &pt1, const QPointF &pt2) { 0173 return pow2(pt1.x() - pt2.x()) + pow2(pt1.y() - pt2.y()); 0174 } 0175 0176 template<typename PointType> 0177 inline PointType snapToClosestAxis(PointType P) { 0178 if (qAbs(P.x()) < qAbs(P.y())) { 0179 P.setX(0); 0180 } else { 0181 P.setY(0); 0182 } 0183 return P; 0184 } 0185 0186 template<typename PointType> 0187 inline PointType snapToClosestNiceAngle(PointType point, PointType startPoint, qreal angle = (2 * M_PI) / 24) { 0188 // default angle = 15 degrees 0189 0190 const QPointF lineVector = point - startPoint; 0191 qreal lineAngle = std::atan2(lineVector.y(), lineVector.x()); 0192 0193 if (lineAngle < 0) { 0194 lineAngle += 2 * M_PI; 0195 } 0196 0197 const quint32 constrainedLineIndex = static_cast<quint32>((lineAngle / angle) + 0.5); 0198 const qreal constrainedLineAngle = constrainedLineIndex * angle; 0199 0200 const qreal lineLength = kisDistance(lineVector, QPointF()); 0201 0202 const QPointF constrainedLineVector(lineLength * std::cos(constrainedLineAngle), lineLength * std::sin(constrainedLineAngle)); 0203 0204 const QPointF result = startPoint + constrainedLineVector; 0205 0206 return result; 0207 } 0208 0209 0210 #include <QLineF> 0211 0212 inline qreal kisDistanceToLine(const QPointF &m, const QLineF &line) 0213 { 0214 const QPointF &p1 = line.p1(); 0215 const QPointF &p2 = line.p2(); 0216 0217 qreal distance = 0; 0218 0219 if (qFuzzyCompare(p1.x(), p2.x())) { 0220 distance = qAbs(m.x() - p2.x()); 0221 } else if (qFuzzyCompare(p1.y(), p2.y())) { 0222 distance = qAbs(m.y() - p2.y()); 0223 } else { 0224 qreal A = 1; 0225 qreal B = - (p1.x() - p2.x()) / (p1.y() - p2.y()); 0226 qreal C = - p1.x() - B * p1.y(); 0227 0228 distance = qAbs(A * m.x() + B * m.y() + C) / std::sqrt(pow2(A) + pow2(B)); 0229 } 0230 0231 return distance; 0232 } 0233 0234 inline QPointF kisProjectOnVector(const QPointF &base, const QPointF &v) 0235 { 0236 const qreal prod = base.x() * v.x() + base.y() * v.y(); 0237 const qreal lengthSq = pow2(base.x()) + pow2(base.y()); 0238 qreal coeff = prod / lengthSq; 0239 0240 return coeff * base; 0241 } 0242 0243 #include <QRect> 0244 0245 inline QRect kisEnsureInRect(QRect rc, const QRect &bounds) 0246 { 0247 if(rc.right() > bounds.right()) { 0248 rc.translate(bounds.right() - rc.right(), 0); 0249 } 0250 0251 if(rc.left() < bounds.left()) { 0252 rc.translate(bounds.left() - rc.left(), 0); 0253 } 0254 0255 if(rc.bottom() > bounds.bottom()) { 0256 rc.translate(0, bounds.bottom() - rc.bottom()); 0257 } 0258 0259 if(rc.top() < bounds.top()) { 0260 rc.translate(0, bounds.top() - rc.top()); 0261 } 0262 0263 return rc; 0264 } 0265 0266 inline QRectF kisTrimLeft( int width, QRectF &toTakeFrom) 0267 { 0268 QPointF trimmedOrigin = toTakeFrom.topLeft(); 0269 QSize trimmedSize = QSize(width, toTakeFrom.height()); 0270 toTakeFrom.setWidth(toTakeFrom.width() - width); 0271 toTakeFrom.translate(width, 0); 0272 return QRectF(trimmedOrigin, trimmedSize); 0273 } 0274 0275 inline QRect kisTrimLeft( int width, QRect &toTakeFrom) 0276 { 0277 QRectF converted = QRectF(toTakeFrom); 0278 QRectF toReturn = kisTrimLeft(width, converted); 0279 toTakeFrom = converted.toAlignedRect(); 0280 return toReturn.toAlignedRect(); 0281 } 0282 0283 inline QRectF kisTrimTop( int height, QRectF& toTakeFrom) 0284 { 0285 QPointF trimmedOrigin = toTakeFrom.topLeft(); 0286 QSize trimmedSize = QSize(toTakeFrom.width(), height); 0287 toTakeFrom.setHeight(toTakeFrom.height() - height); 0288 toTakeFrom.translate(0, height); 0289 return QRectF(trimmedOrigin, trimmedSize); 0290 } 0291 0292 inline QRect kisTrimTop( int height, QRect& toTakeFrom) 0293 { 0294 QRectF converted = QRectF(toTakeFrom); 0295 QRectF toReturn = kisTrimTop(height, converted); 0296 toTakeFrom = converted.toAlignedRect(); 0297 return toReturn.toAlignedRect(); 0298 } 0299 0300 #include "kis_pointer_utils.h" 0301 #include <type_traits> 0302 0303 // Makes compilers happy because Linux and macOS differ on how they define 0304 // quint64 (unsigned long long) vs. size_t (unsigned long (int)). 0305 template <typename T> 0306 inline T nextPowerOfTwo(T v) 0307 { 0308 static_assert(std::is_integral<T>::value, "Value has to be an integral number"); 0309 using base_type = typename std::conditional<sizeof(T) == sizeof(quint64), quint64, quint32>::type; 0310 using common_type = typename std::conditional<std::is_signed<T>::value, typename std::make_signed<base_type>::type, typename std::make_unsigned<base_type>::type>::type; 0311 return static_cast<T>(qNextPowerOfTwo(static_cast<common_type>(v))); 0312 } 0313 0314 #endif // KISGLOBAL_H_ 0315